2 * Copyright (C) 2005 - 2009 ServerEngines
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation. The full GNU General
8 * Public License is included in this distribution in the file called COPYING.
10 * Contact Information:
11 * linux-drivers@serverengines.com
14 * 209 N. Fair Oaks Ave
19 #include <linux/ethtool.h>
21 struct be_ethtool_stat
{
22 char desc
[ETH_GSTRING_LEN
];
28 enum {NETSTAT
, PORTSTAT
, MISCSTAT
, DRVSTAT
, ERXSTAT
};
29 #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
30 offsetof(_struct, field)
31 #define NETSTAT_INFO(field) #field, NETSTAT,\
32 FIELDINFO(struct net_device_stats,\
34 #define DRVSTAT_INFO(field) #field, DRVSTAT,\
35 FIELDINFO(struct be_drvr_stats, field)
36 #define MISCSTAT_INFO(field) #field, MISCSTAT,\
37 FIELDINFO(struct be_rxf_stats, field)
38 #define PORTSTAT_INFO(field) #field, PORTSTAT,\
39 FIELDINFO(struct be_port_rxf_stats, \
41 #define ERXSTAT_INFO(field) #field, ERXSTAT,\
42 FIELDINFO(struct be_erx_stats, field)
44 static const struct be_ethtool_stat et_stats
[] = {
45 {NETSTAT_INFO(rx_packets
)},
46 {NETSTAT_INFO(tx_packets
)},
47 {NETSTAT_INFO(rx_bytes
)},
48 {NETSTAT_INFO(tx_bytes
)},
49 {NETSTAT_INFO(rx_errors
)},
50 {NETSTAT_INFO(tx_errors
)},
51 {NETSTAT_INFO(rx_dropped
)},
52 {NETSTAT_INFO(tx_dropped
)},
53 {DRVSTAT_INFO(be_tx_reqs
)},
54 {DRVSTAT_INFO(be_tx_stops
)},
55 {DRVSTAT_INFO(be_fwd_reqs
)},
56 {DRVSTAT_INFO(be_tx_wrbs
)},
57 {DRVSTAT_INFO(be_polls
)},
58 {DRVSTAT_INFO(be_tx_events
)},
59 {DRVSTAT_INFO(be_rx_events
)},
60 {DRVSTAT_INFO(be_tx_compl
)},
61 {DRVSTAT_INFO(be_rx_compl
)},
62 {DRVSTAT_INFO(be_ethrx_post_fail
)},
63 {DRVSTAT_INFO(be_802_3_dropped_frames
)},
64 {DRVSTAT_INFO(be_802_3_malformed_frames
)},
65 {DRVSTAT_INFO(be_tx_rate
)},
66 {DRVSTAT_INFO(be_rx_rate
)},
67 {PORTSTAT_INFO(rx_unicast_frames
)},
68 {PORTSTAT_INFO(rx_multicast_frames
)},
69 {PORTSTAT_INFO(rx_broadcast_frames
)},
70 {PORTSTAT_INFO(rx_crc_errors
)},
71 {PORTSTAT_INFO(rx_alignment_symbol_errors
)},
72 {PORTSTAT_INFO(rx_pause_frames
)},
73 {PORTSTAT_INFO(rx_control_frames
)},
74 {PORTSTAT_INFO(rx_in_range_errors
)},
75 {PORTSTAT_INFO(rx_out_range_errors
)},
76 {PORTSTAT_INFO(rx_frame_too_long
)},
77 {PORTSTAT_INFO(rx_address_match_errors
)},
78 {PORTSTAT_INFO(rx_vlan_mismatch
)},
79 {PORTSTAT_INFO(rx_dropped_too_small
)},
80 {PORTSTAT_INFO(rx_dropped_too_short
)},
81 {PORTSTAT_INFO(rx_dropped_header_too_small
)},
82 {PORTSTAT_INFO(rx_dropped_tcp_length
)},
83 {PORTSTAT_INFO(rx_dropped_runt
)},
84 {PORTSTAT_INFO(rx_fifo_overflow
)},
85 {PORTSTAT_INFO(rx_input_fifo_overflow
)},
86 {PORTSTAT_INFO(rx_ip_checksum_errs
)},
87 {PORTSTAT_INFO(rx_tcp_checksum_errs
)},
88 {PORTSTAT_INFO(rx_udp_checksum_errs
)},
89 {PORTSTAT_INFO(rx_non_rss_packets
)},
90 {PORTSTAT_INFO(rx_ipv4_packets
)},
91 {PORTSTAT_INFO(rx_ipv6_packets
)},
92 {PORTSTAT_INFO(tx_unicastframes
)},
93 {PORTSTAT_INFO(tx_multicastframes
)},
94 {PORTSTAT_INFO(tx_broadcastframes
)},
95 {PORTSTAT_INFO(tx_pauseframes
)},
96 {PORTSTAT_INFO(tx_controlframes
)},
97 {MISCSTAT_INFO(rx_drops_no_pbuf
)},
98 {MISCSTAT_INFO(rx_drops_no_txpb
)},
99 {MISCSTAT_INFO(rx_drops_no_erx_descr
)},
100 {MISCSTAT_INFO(rx_drops_no_tpre_descr
)},
101 {MISCSTAT_INFO(rx_drops_too_many_frags
)},
102 {MISCSTAT_INFO(rx_drops_invalid_ring
)},
103 {MISCSTAT_INFO(forwarded_packets
)},
104 {MISCSTAT_INFO(rx_drops_mtu
)},
105 {ERXSTAT_INFO(rx_drops_no_fragments
)},
107 #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
110 be_get_drvinfo(struct net_device
*netdev
, struct ethtool_drvinfo
*drvinfo
)
112 struct be_adapter
*adapter
= netdev_priv(netdev
);
114 strcpy(drvinfo
->driver
, DRV_NAME
);
115 strcpy(drvinfo
->version
, DRV_VER
);
116 strncpy(drvinfo
->fw_version
, adapter
->fw_ver
, FW_VER_LEN
);
117 strcpy(drvinfo
->bus_info
, pci_name(adapter
->pdev
));
118 drvinfo
->testinfo_len
= 0;
119 drvinfo
->regdump_len
= 0;
120 drvinfo
->eedump_len
= 0;
124 be_get_coalesce(struct net_device
*netdev
, struct ethtool_coalesce
*coalesce
)
126 struct be_adapter
*adapter
= netdev_priv(netdev
);
127 struct be_eq_obj
*rx_eq
= &adapter
->rx_eq
;
128 struct be_eq_obj
*tx_eq
= &adapter
->tx_eq
;
130 coalesce
->rx_max_coalesced_frames
= adapter
->max_rx_coal
;
132 coalesce
->rx_coalesce_usecs
= rx_eq
->cur_eqd
;
133 coalesce
->rx_coalesce_usecs_high
= rx_eq
->max_eqd
;
134 coalesce
->rx_coalesce_usecs_low
= rx_eq
->min_eqd
;
136 coalesce
->tx_coalesce_usecs
= tx_eq
->cur_eqd
;
137 coalesce
->tx_coalesce_usecs_high
= tx_eq
->max_eqd
;
138 coalesce
->tx_coalesce_usecs_low
= tx_eq
->min_eqd
;
140 coalesce
->use_adaptive_rx_coalesce
= rx_eq
->enable_aic
;
141 coalesce
->use_adaptive_tx_coalesce
= tx_eq
->enable_aic
;
147 * This routine is used to set interrup coalescing delay *as well as*
148 * the number of pkts to coalesce for LRO.
151 be_set_coalesce(struct net_device
*netdev
, struct ethtool_coalesce
*coalesce
)
153 struct be_adapter
*adapter
= netdev_priv(netdev
);
154 struct be_ctrl_info
*ctrl
= &adapter
->ctrl
;
155 struct be_eq_obj
*rx_eq
= &adapter
->rx_eq
;
156 struct be_eq_obj
*tx_eq
= &adapter
->tx_eq
;
157 u32 tx_max
, tx_min
, tx_cur
;
158 u32 rx_max
, rx_min
, rx_cur
;
161 if (coalesce
->use_adaptive_tx_coalesce
== 1)
164 adapter
->max_rx_coal
= coalesce
->rx_max_coalesced_frames
;
165 if (adapter
->max_rx_coal
> MAX_SKB_FRAGS
)
166 adapter
->max_rx_coal
= MAX_SKB_FRAGS
- 1;
168 /* if AIC is being turned on now, start with an EQD of 0 */
169 if (rx_eq
->enable_aic
== 0 &&
170 coalesce
->use_adaptive_rx_coalesce
== 1) {
173 rx_eq
->enable_aic
= coalesce
->use_adaptive_rx_coalesce
;
175 rx_max
= coalesce
->rx_coalesce_usecs_high
;
176 rx_min
= coalesce
->rx_coalesce_usecs_low
;
177 rx_cur
= coalesce
->rx_coalesce_usecs
;
179 tx_max
= coalesce
->tx_coalesce_usecs_high
;
180 tx_min
= coalesce
->tx_coalesce_usecs_low
;
181 tx_cur
= coalesce
->tx_coalesce_usecs
;
183 if (tx_cur
> BE_MAX_EQD
)
185 if (tx_eq
->cur_eqd
!= tx_cur
) {
186 status
= be_cmd_modify_eqd(ctrl
, tx_eq
->q
.id
, tx_cur
);
188 tx_eq
->cur_eqd
= tx_cur
;
191 if (rx_eq
->enable_aic
) {
192 if (rx_max
> BE_MAX_EQD
)
196 rx_eq
->max_eqd
= rx_max
;
197 rx_eq
->min_eqd
= rx_min
;
198 if (rx_eq
->cur_eqd
> rx_max
)
199 rx_eq
->cur_eqd
= rx_max
;
200 if (rx_eq
->cur_eqd
< rx_min
)
201 rx_eq
->cur_eqd
= rx_min
;
203 if (rx_cur
> BE_MAX_EQD
)
205 if (rx_eq
->cur_eqd
!= rx_cur
) {
206 status
= be_cmd_modify_eqd(ctrl
, rx_eq
->q
.id
, rx_cur
);
208 rx_eq
->cur_eqd
= rx_cur
;
214 static u32
be_get_rx_csum(struct net_device
*netdev
)
216 struct be_adapter
*adapter
= netdev_priv(netdev
);
218 return adapter
->rx_csum
;
221 static int be_set_rx_csum(struct net_device
*netdev
, uint32_t data
)
223 struct be_adapter
*adapter
= netdev_priv(netdev
);
226 adapter
->rx_csum
= true;
228 adapter
->rx_csum
= false;
234 be_get_ethtool_stats(struct net_device
*netdev
,
235 struct ethtool_stats
*stats
, uint64_t *data
)
237 struct be_adapter
*adapter
= netdev_priv(netdev
);
238 struct be_drvr_stats
*drvr_stats
= &adapter
->stats
.drvr_stats
;
239 struct be_hw_stats
*hw_stats
= hw_stats_from_cmd(adapter
->stats
.cmd
.va
);
240 struct be_rxf_stats
*rxf_stats
= &hw_stats
->rxf
;
241 struct be_port_rxf_stats
*port_stats
=
242 &rxf_stats
->port
[adapter
->port_num
];
243 struct net_device_stats
*net_stats
= &adapter
->stats
.net_stats
;
244 struct be_erx_stats
*erx_stats
= &hw_stats
->erx
;
248 for (i
= 0; i
< ETHTOOL_STATS_NUM
; i
++) {
249 switch (et_stats
[i
].type
) {
262 case ERXSTAT
: /* Currently only one ERX stat is provided */
263 p
= (u32
*)erx_stats
+ adapter
->rx_obj
.q
.id
;
267 p
= (u8
*)p
+ et_stats
[i
].offset
;
268 data
[i
] = (et_stats
[i
].size
== sizeof(u64
)) ?
269 *(u64
*)p
: *(u32
*)p
;
276 be_get_stat_strings(struct net_device
*netdev
, uint32_t stringset
,
282 for (i
= 0; i
< ETHTOOL_STATS_NUM
; i
++) {
283 memcpy(data
, et_stats
[i
].desc
, ETH_GSTRING_LEN
);
284 data
+= ETH_GSTRING_LEN
;
290 static int be_get_stats_count(struct net_device
*netdev
)
292 return ETHTOOL_STATS_NUM
;
295 static int be_get_settings(struct net_device
*netdev
, struct ethtool_cmd
*ecmd
)
297 ecmd
->speed
= SPEED_10000
;
298 ecmd
->duplex
= DUPLEX_FULL
;
299 ecmd
->autoneg
= AUTONEG_DISABLE
;
304 be_get_ringparam(struct net_device
*netdev
, struct ethtool_ringparam
*ring
)
306 struct be_adapter
*adapter
= netdev_priv(netdev
);
308 ring
->rx_max_pending
= adapter
->rx_obj
.q
.len
;
309 ring
->tx_max_pending
= adapter
->tx_obj
.q
.len
;
311 ring
->rx_pending
= atomic_read(&adapter
->rx_obj
.q
.used
);
312 ring
->tx_pending
= atomic_read(&adapter
->tx_obj
.q
.used
);
316 be_get_pauseparam(struct net_device
*netdev
, struct ethtool_pauseparam
*ecmd
)
318 struct be_adapter
*adapter
= netdev_priv(netdev
);
320 be_cmd_get_flow_control(&adapter
->ctrl
, &ecmd
->tx_pause
,
326 be_set_pauseparam(struct net_device
*netdev
, struct ethtool_pauseparam
*ecmd
)
328 struct be_adapter
*adapter
= netdev_priv(netdev
);
331 if (ecmd
->autoneg
!= 0)
334 status
= be_cmd_set_flow_control(&adapter
->ctrl
, ecmd
->tx_pause
,
337 dev_warn(&adapter
->pdev
->dev
, "Pause param set failed.\n");
342 struct ethtool_ops be_ethtool_ops
= {
343 .get_settings
= be_get_settings
,
344 .get_drvinfo
= be_get_drvinfo
,
345 .get_link
= ethtool_op_get_link
,
346 .get_coalesce
= be_get_coalesce
,
347 .set_coalesce
= be_set_coalesce
,
348 .get_ringparam
= be_get_ringparam
,
349 .get_pauseparam
= be_get_pauseparam
,
350 .set_pauseparam
= be_set_pauseparam
,
351 .get_rx_csum
= be_get_rx_csum
,
352 .set_rx_csum
= be_set_rx_csum
,
353 .get_tx_csum
= ethtool_op_get_tx_csum
,
354 .set_tx_csum
= ethtool_op_set_tx_csum
,
355 .get_sg
= ethtool_op_get_sg
,
356 .set_sg
= ethtool_op_set_sg
,
357 .get_tso
= ethtool_op_get_tso
,
358 .set_tso
= ethtool_op_set_tso
,
359 .get_strings
= be_get_stat_strings
,
360 .get_stats_count
= be_get_stats_count
,
361 .get_ethtool_stats
= be_get_ethtool_stats
,