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
20 #include <linux/ethtool.h>
22 struct be_ethtool_stat
{
23 char desc
[ETH_GSTRING_LEN
];
29 enum {NETSTAT
, PORTSTAT
, MISCSTAT
, DRVSTAT
, ERXSTAT
};
30 #define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
31 offsetof(_struct, field)
32 #define NETSTAT_INFO(field) #field, NETSTAT,\
33 FIELDINFO(struct net_device_stats,\
35 #define DRVSTAT_INFO(field) #field, DRVSTAT,\
36 FIELDINFO(struct be_drvr_stats, field)
37 #define MISCSTAT_INFO(field) #field, MISCSTAT,\
38 FIELDINFO(struct be_rxf_stats, field)
39 #define PORTSTAT_INFO(field) #field, PORTSTAT,\
40 FIELDINFO(struct be_port_rxf_stats, \
42 #define ERXSTAT_INFO(field) #field, ERXSTAT,\
43 FIELDINFO(struct be_erx_stats, field)
45 static const struct be_ethtool_stat et_stats
[] = {
46 {NETSTAT_INFO(rx_packets
)},
47 {NETSTAT_INFO(tx_packets
)},
48 {NETSTAT_INFO(rx_bytes
)},
49 {NETSTAT_INFO(tx_bytes
)},
50 {NETSTAT_INFO(rx_errors
)},
51 {NETSTAT_INFO(tx_errors
)},
52 {NETSTAT_INFO(rx_dropped
)},
53 {NETSTAT_INFO(tx_dropped
)},
54 {DRVSTAT_INFO(be_tx_reqs
)},
55 {DRVSTAT_INFO(be_tx_stops
)},
56 {DRVSTAT_INFO(be_fwd_reqs
)},
57 {DRVSTAT_INFO(be_tx_wrbs
)},
58 {DRVSTAT_INFO(be_polls
)},
59 {DRVSTAT_INFO(be_tx_events
)},
60 {DRVSTAT_INFO(be_rx_events
)},
61 {DRVSTAT_INFO(be_tx_compl
)},
62 {DRVSTAT_INFO(be_rx_compl
)},
63 {DRVSTAT_INFO(be_ethrx_post_fail
)},
64 {DRVSTAT_INFO(be_802_3_dropped_frames
)},
65 {DRVSTAT_INFO(be_802_3_malformed_frames
)},
66 {DRVSTAT_INFO(be_tx_rate
)},
67 {DRVSTAT_INFO(be_rx_rate
)},
68 {PORTSTAT_INFO(rx_unicast_frames
)},
69 {PORTSTAT_INFO(rx_multicast_frames
)},
70 {PORTSTAT_INFO(rx_broadcast_frames
)},
71 {PORTSTAT_INFO(rx_crc_errors
)},
72 {PORTSTAT_INFO(rx_alignment_symbol_errors
)},
73 {PORTSTAT_INFO(rx_pause_frames
)},
74 {PORTSTAT_INFO(rx_control_frames
)},
75 {PORTSTAT_INFO(rx_in_range_errors
)},
76 {PORTSTAT_INFO(rx_out_range_errors
)},
77 {PORTSTAT_INFO(rx_frame_too_long
)},
78 {PORTSTAT_INFO(rx_address_match_errors
)},
79 {PORTSTAT_INFO(rx_vlan_mismatch
)},
80 {PORTSTAT_INFO(rx_dropped_too_small
)},
81 {PORTSTAT_INFO(rx_dropped_too_short
)},
82 {PORTSTAT_INFO(rx_dropped_header_too_small
)},
83 {PORTSTAT_INFO(rx_dropped_tcp_length
)},
84 {PORTSTAT_INFO(rx_dropped_runt
)},
85 {PORTSTAT_INFO(rx_fifo_overflow
)},
86 {PORTSTAT_INFO(rx_input_fifo_overflow
)},
87 {PORTSTAT_INFO(rx_ip_checksum_errs
)},
88 {PORTSTAT_INFO(rx_tcp_checksum_errs
)},
89 {PORTSTAT_INFO(rx_udp_checksum_errs
)},
90 {PORTSTAT_INFO(rx_non_rss_packets
)},
91 {PORTSTAT_INFO(rx_ipv4_packets
)},
92 {PORTSTAT_INFO(rx_ipv6_packets
)},
93 {PORTSTAT_INFO(tx_unicastframes
)},
94 {PORTSTAT_INFO(tx_multicastframes
)},
95 {PORTSTAT_INFO(tx_broadcastframes
)},
96 {PORTSTAT_INFO(tx_pauseframes
)},
97 {PORTSTAT_INFO(tx_controlframes
)},
98 {MISCSTAT_INFO(rx_drops_no_pbuf
)},
99 {MISCSTAT_INFO(rx_drops_no_txpb
)},
100 {MISCSTAT_INFO(rx_drops_no_erx_descr
)},
101 {MISCSTAT_INFO(rx_drops_no_tpre_descr
)},
102 {MISCSTAT_INFO(rx_drops_too_many_frags
)},
103 {MISCSTAT_INFO(rx_drops_invalid_ring
)},
104 {MISCSTAT_INFO(forwarded_packets
)},
105 {MISCSTAT_INFO(rx_drops_mtu
)},
106 {ERXSTAT_INFO(rx_drops_no_fragments
)},
108 #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
111 be_get_drvinfo(struct net_device
*netdev
, struct ethtool_drvinfo
*drvinfo
)
113 struct be_adapter
*adapter
= netdev_priv(netdev
);
115 strcpy(drvinfo
->driver
, DRV_NAME
);
116 strcpy(drvinfo
->version
, DRV_VER
);
117 strncpy(drvinfo
->fw_version
, adapter
->fw_ver
, FW_VER_LEN
);
118 strcpy(drvinfo
->bus_info
, pci_name(adapter
->pdev
));
119 drvinfo
->testinfo_len
= 0;
120 drvinfo
->regdump_len
= 0;
121 drvinfo
->eedump_len
= 0;
125 be_get_coalesce(struct net_device
*netdev
, struct ethtool_coalesce
*coalesce
)
127 struct be_adapter
*adapter
= netdev_priv(netdev
);
128 struct be_eq_obj
*rx_eq
= &adapter
->rx_eq
;
129 struct be_eq_obj
*tx_eq
= &adapter
->tx_eq
;
131 coalesce
->rx_coalesce_usecs
= rx_eq
->cur_eqd
;
132 coalesce
->rx_coalesce_usecs_high
= rx_eq
->max_eqd
;
133 coalesce
->rx_coalesce_usecs_low
= rx_eq
->min_eqd
;
135 coalesce
->tx_coalesce_usecs
= tx_eq
->cur_eqd
;
136 coalesce
->tx_coalesce_usecs_high
= tx_eq
->max_eqd
;
137 coalesce
->tx_coalesce_usecs_low
= tx_eq
->min_eqd
;
139 coalesce
->use_adaptive_rx_coalesce
= rx_eq
->enable_aic
;
140 coalesce
->use_adaptive_tx_coalesce
= tx_eq
->enable_aic
;
146 * This routine is used to set interrup coalescing delay
149 be_set_coalesce(struct net_device
*netdev
, struct ethtool_coalesce
*coalesce
)
151 struct be_adapter
*adapter
= netdev_priv(netdev
);
152 struct be_eq_obj
*rx_eq
= &adapter
->rx_eq
;
153 struct be_eq_obj
*tx_eq
= &adapter
->tx_eq
;
154 u32 tx_max
, tx_min
, tx_cur
;
155 u32 rx_max
, rx_min
, rx_cur
;
158 if (coalesce
->use_adaptive_tx_coalesce
== 1)
161 /* if AIC is being turned on now, start with an EQD of 0 */
162 if (rx_eq
->enable_aic
== 0 &&
163 coalesce
->use_adaptive_rx_coalesce
== 1) {
166 rx_eq
->enable_aic
= coalesce
->use_adaptive_rx_coalesce
;
168 rx_max
= coalesce
->rx_coalesce_usecs_high
;
169 rx_min
= coalesce
->rx_coalesce_usecs_low
;
170 rx_cur
= coalesce
->rx_coalesce_usecs
;
172 tx_max
= coalesce
->tx_coalesce_usecs_high
;
173 tx_min
= coalesce
->tx_coalesce_usecs_low
;
174 tx_cur
= coalesce
->tx_coalesce_usecs
;
176 if (tx_cur
> BE_MAX_EQD
)
178 if (tx_eq
->cur_eqd
!= tx_cur
) {
179 status
= be_cmd_modify_eqd(adapter
, tx_eq
->q
.id
, tx_cur
);
181 tx_eq
->cur_eqd
= tx_cur
;
184 if (rx_eq
->enable_aic
) {
185 if (rx_max
> BE_MAX_EQD
)
189 rx_eq
->max_eqd
= rx_max
;
190 rx_eq
->min_eqd
= rx_min
;
191 if (rx_eq
->cur_eqd
> rx_max
)
192 rx_eq
->cur_eqd
= rx_max
;
193 if (rx_eq
->cur_eqd
< rx_min
)
194 rx_eq
->cur_eqd
= rx_min
;
196 if (rx_cur
> BE_MAX_EQD
)
198 if (rx_eq
->cur_eqd
!= rx_cur
) {
199 status
= be_cmd_modify_eqd(adapter
, rx_eq
->q
.id
,
202 rx_eq
->cur_eqd
= rx_cur
;
208 static u32
be_get_rx_csum(struct net_device
*netdev
)
210 struct be_adapter
*adapter
= netdev_priv(netdev
);
212 return adapter
->rx_csum
;
215 static int be_set_rx_csum(struct net_device
*netdev
, uint32_t data
)
217 struct be_adapter
*adapter
= netdev_priv(netdev
);
220 adapter
->rx_csum
= true;
222 adapter
->rx_csum
= false;
228 be_get_ethtool_stats(struct net_device
*netdev
,
229 struct ethtool_stats
*stats
, uint64_t *data
)
231 struct be_adapter
*adapter
= netdev_priv(netdev
);
232 struct be_drvr_stats
*drvr_stats
= &adapter
->stats
.drvr_stats
;
233 struct be_hw_stats
*hw_stats
= hw_stats_from_cmd(adapter
->stats
.cmd
.va
);
234 struct be_rxf_stats
*rxf_stats
= &hw_stats
->rxf
;
235 struct be_port_rxf_stats
*port_stats
=
236 &rxf_stats
->port
[adapter
->port_num
];
237 struct net_device_stats
*net_stats
= &adapter
->stats
.net_stats
;
238 struct be_erx_stats
*erx_stats
= &hw_stats
->erx
;
242 for (i
= 0; i
< ETHTOOL_STATS_NUM
; i
++) {
243 switch (et_stats
[i
].type
) {
256 case ERXSTAT
: /* Currently only one ERX stat is provided */
257 p
= (u32
*)erx_stats
+ adapter
->rx_obj
.q
.id
;
261 p
= (u8
*)p
+ et_stats
[i
].offset
;
262 data
[i
] = (et_stats
[i
].size
== sizeof(u64
)) ?
263 *(u64
*)p
: *(u32
*)p
;
270 be_get_stat_strings(struct net_device
*netdev
, uint32_t stringset
,
276 for (i
= 0; i
< ETHTOOL_STATS_NUM
; i
++) {
277 memcpy(data
, et_stats
[i
].desc
, ETH_GSTRING_LEN
);
278 data
+= ETH_GSTRING_LEN
;
284 static int be_get_stats_count(struct net_device
*netdev
)
286 return ETHTOOL_STATS_NUM
;
289 static int be_get_settings(struct net_device
*netdev
, struct ethtool_cmd
*ecmd
)
291 ecmd
->speed
= SPEED_10000
;
292 ecmd
->duplex
= DUPLEX_FULL
;
293 ecmd
->autoneg
= AUTONEG_DISABLE
;
298 be_get_ringparam(struct net_device
*netdev
, struct ethtool_ringparam
*ring
)
300 struct be_adapter
*adapter
= netdev_priv(netdev
);
302 ring
->rx_max_pending
= adapter
->rx_obj
.q
.len
;
303 ring
->tx_max_pending
= adapter
->tx_obj
.q
.len
;
305 ring
->rx_pending
= atomic_read(&adapter
->rx_obj
.q
.used
);
306 ring
->tx_pending
= atomic_read(&adapter
->tx_obj
.q
.used
);
310 be_get_pauseparam(struct net_device
*netdev
, struct ethtool_pauseparam
*ecmd
)
312 struct be_adapter
*adapter
= netdev_priv(netdev
);
314 be_cmd_get_flow_control(adapter
, &ecmd
->tx_pause
, &ecmd
->rx_pause
);
319 be_set_pauseparam(struct net_device
*netdev
, struct ethtool_pauseparam
*ecmd
)
321 struct be_adapter
*adapter
= netdev_priv(netdev
);
324 if (ecmd
->autoneg
!= 0)
327 status
= be_cmd_set_flow_control(adapter
, ecmd
->tx_pause
,
330 dev_warn(&adapter
->pdev
->dev
, "Pause param set failed.\n");
336 be_do_flash(struct net_device
*netdev
, struct ethtool_flash
*efl
)
338 struct be_adapter
*adapter
= netdev_priv(netdev
);
339 char file_name
[ETHTOOL_FLASH_MAX_FILENAME
];
342 file_name
[ETHTOOL_FLASH_MAX_FILENAME
- 1] = 0;
343 strcpy(file_name
, efl
->data
);
344 region
= efl
->region
;
346 return be_load_fw(adapter
, file_name
);
349 const struct ethtool_ops be_ethtool_ops
= {
350 .get_settings
= be_get_settings
,
351 .get_drvinfo
= be_get_drvinfo
,
352 .get_link
= ethtool_op_get_link
,
353 .get_coalesce
= be_get_coalesce
,
354 .set_coalesce
= be_set_coalesce
,
355 .get_ringparam
= be_get_ringparam
,
356 .get_pauseparam
= be_get_pauseparam
,
357 .set_pauseparam
= be_set_pauseparam
,
358 .get_rx_csum
= be_get_rx_csum
,
359 .set_rx_csum
= be_set_rx_csum
,
360 .get_tx_csum
= ethtool_op_get_tx_csum
,
361 .set_tx_csum
= ethtool_op_set_tx_hw_csum
,
362 .get_sg
= ethtool_op_get_sg
,
363 .set_sg
= ethtool_op_set_sg
,
364 .get_tso
= ethtool_op_get_tso
,
365 .set_tso
= ethtool_op_set_tso
,
366 .get_strings
= be_get_stat_strings
,
367 .get_stats_count
= be_get_stats_count
,
368 .get_ethtool_stats
= be_get_ethtool_stats
,
369 .flash_device
= be_do_flash
,