]>
Commit | Line | Data |
---|---|---|
7a291083 | 1 | /* |
3396c782 | 2 | * linux/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c |
7a291083 JBT |
3 | * |
4 | * eHEA ethernet device driver for IBM eServer System p | |
5 | * | |
6 | * (C) Copyright IBM Corp. 2006 | |
7 | * | |
8 | * Authors: | |
9 | * Christoph Raisch <raisch@de.ibm.com> | |
10 | * Jan-Bernd Themann <themann@de.ibm.com> | |
11 | * Thomas Klein <tklein@de.ibm.com> | |
12 | * | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2, or (at your option) | |
17 | * any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License | |
25 | * along with this program; if not, write to the Free Software | |
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
27 | */ | |
28 | ||
8c4877a4 JP |
29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
30 | ||
7a291083 JBT |
31 | #include "ehea.h" |
32 | #include "ehea_phyp.h" | |
33 | ||
34 | static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
35 | { | |
36 | struct ehea_port *port = netdev_priv(dev); | |
70739497 | 37 | u32 speed; |
7a291083 JBT |
38 | int ret; |
39 | ||
40 | ret = ehea_sense_port_attr(port); | |
41 | ||
42 | if (ret) | |
43 | return ret; | |
44 | ||
45 | if (netif_carrier_ok(dev)) { | |
13da93d4 | 46 | switch (port->port_speed) { |
70739497 DD |
47 | case EHEA_SPEED_10M: |
48 | speed = SPEED_10; | |
49 | break; | |
50 | case EHEA_SPEED_100M: | |
51 | speed = SPEED_100; | |
52 | break; | |
53 | case EHEA_SPEED_1G: | |
54 | speed = SPEED_1000; | |
55 | break; | |
56 | case EHEA_SPEED_10G: | |
57 | speed = SPEED_10000; | |
58 | break; | |
59 | default: | |
60 | speed = -1; | |
61 | break; /* BUG */ | |
7a291083 JBT |
62 | } |
63 | cmd->duplex = port->full_duplex == 1 ? | |
64 | DUPLEX_FULL : DUPLEX_HALF; | |
65 | } else { | |
70739497 | 66 | speed = ~0; |
7a291083 JBT |
67 | cmd->duplex = -1; |
68 | } | |
70739497 | 69 | ethtool_cmd_speed_set(cmd, speed); |
7a291083 | 70 | |
dcbe14b9 KSS |
71 | if (cmd->speed == SPEED_10000) { |
72 | cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); | |
73 | cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); | |
74 | cmd->port = PORT_FIBRE; | |
75 | } else { | |
76 | cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full | |
77 | | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full | |
78 | | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg | |
79 | | SUPPORTED_TP); | |
80 | cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | |
81 | | ADVERTISED_TP); | |
82 | cmd->port = PORT_TP; | |
83 | } | |
7a291083 | 84 | |
7a291083 JBT |
85 | cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE; |
86 | ||
87 | return 0; | |
88 | } | |
89 | ||
90 | static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
91 | { | |
92 | struct ehea_port *port = netdev_priv(dev); | |
93 | int ret = 0; | |
94 | u32 sp; | |
95 | ||
96 | if (cmd->autoneg == AUTONEG_ENABLE) { | |
97 | sp = EHEA_SPEED_AUTONEG; | |
98 | goto doit; | |
99 | } | |
100 | ||
13da93d4 | 101 | switch (cmd->speed) { |
7a291083 JBT |
102 | case SPEED_10: |
103 | if (cmd->duplex == DUPLEX_FULL) | |
104 | sp = H_SPEED_10M_F; | |
105 | else | |
106 | sp = H_SPEED_10M_H; | |
107 | break; | |
108 | ||
109 | case SPEED_100: | |
110 | if (cmd->duplex == DUPLEX_FULL) | |
111 | sp = H_SPEED_100M_F; | |
112 | else | |
113 | sp = H_SPEED_100M_H; | |
114 | break; | |
115 | ||
116 | case SPEED_1000: | |
117 | if (cmd->duplex == DUPLEX_FULL) | |
118 | sp = H_SPEED_1G_F; | |
119 | else | |
120 | ret = -EINVAL; | |
121 | break; | |
122 | ||
123 | case SPEED_10000: | |
124 | if (cmd->duplex == DUPLEX_FULL) | |
125 | sp = H_SPEED_10G_F; | |
126 | else | |
127 | ret = -EINVAL; | |
128 | break; | |
129 | ||
130 | default: | |
131 | ret = -EINVAL; | |
132 | break; | |
133 | } | |
134 | ||
135 | if (ret) | |
136 | goto out; | |
137 | doit: | |
138 | ret = ehea_set_portspeed(port, sp); | |
139 | ||
140 | if (!ret) | |
8c4877a4 JP |
141 | netdev_info(dev, |
142 | "Port speed successfully set: %dMbps %s Duplex\n", | |
143 | port->port_speed, | |
144 | port->full_duplex == 1 ? "Full" : "Half"); | |
7a291083 JBT |
145 | out: |
146 | return ret; | |
147 | } | |
148 | ||
149 | static int ehea_nway_reset(struct net_device *dev) | |
150 | { | |
151 | struct ehea_port *port = netdev_priv(dev); | |
152 | int ret; | |
153 | ||
154 | ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG); | |
155 | ||
156 | if (!ret) | |
8c4877a4 JP |
157 | netdev_info(port->netdev, |
158 | "Port speed successfully set: %dMbps %s Duplex\n", | |
159 | port->port_speed, | |
160 | port->full_duplex == 1 ? "Full" : "Half"); | |
7a291083 JBT |
161 | return ret; |
162 | } | |
163 | ||
164 | static void ehea_get_drvinfo(struct net_device *dev, | |
165 | struct ethtool_drvinfo *info) | |
166 | { | |
4eccccb3 JD |
167 | strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); |
168 | strlcpy(info->version, DRV_VERSION, sizeof(info->version)); | |
7a291083 JBT |
169 | } |
170 | ||
171 | static u32 ehea_get_msglevel(struct net_device *dev) | |
172 | { | |
173 | struct ehea_port *port = netdev_priv(dev); | |
174 | return port->msg_enable; | |
175 | } | |
176 | ||
177 | static void ehea_set_msglevel(struct net_device *dev, u32 value) | |
178 | { | |
179 | struct ehea_port *port = netdev_priv(dev); | |
180 | port->msg_enable = value; | |
181 | } | |
182 | ||
b9564468 | 183 | static const char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { |
7a291083 JBT |
184 | {"sig_comp_iv"}, |
185 | {"swqe_refill_th"}, | |
186 | {"port resets"}, | |
acbddb59 JBT |
187 | {"Receive errors"}, |
188 | {"TCP cksum errors"}, | |
189 | {"IP cksum errors"}, | |
190 | {"Frame cksum errors"}, | |
191 | {"num SQ stopped"}, | |
acbddb59 JBT |
192 | {"PR0 free_swqes"}, |
193 | {"PR1 free_swqes"}, | |
194 | {"PR2 free_swqes"}, | |
195 | {"PR3 free_swqes"}, | |
196 | {"PR4 free_swqes"}, | |
197 | {"PR5 free_swqes"}, | |
198 | {"PR6 free_swqes"}, | |
199 | {"PR7 free_swqes"}, | |
b9564468 AB |
200 | {"PR8 free_swqes"}, |
201 | {"PR9 free_swqes"}, | |
202 | {"PR10 free_swqes"}, | |
203 | {"PR11 free_swqes"}, | |
204 | {"PR12 free_swqes"}, | |
205 | {"PR13 free_swqes"}, | |
206 | {"PR14 free_swqes"}, | |
207 | {"PR15 free_swqes"}, | |
7a291083 JBT |
208 | }; |
209 | ||
210 | static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) | |
211 | { | |
212 | if (stringset == ETH_SS_STATS) { | |
213 | memcpy(data, &ehea_ethtool_stats_keys, | |
214 | sizeof(ehea_ethtool_stats_keys)); | |
215 | } | |
216 | } | |
217 | ||
b9f2c044 | 218 | static int ehea_get_sset_count(struct net_device *dev, int sset) |
7a291083 | 219 | { |
b9f2c044 JG |
220 | switch (sset) { |
221 | case ETH_SS_STATS: | |
222 | return ARRAY_SIZE(ehea_ethtool_stats_keys); | |
223 | default: | |
224 | return -EOPNOTSUPP; | |
225 | } | |
7a291083 JBT |
226 | } |
227 | ||
228 | static void ehea_get_ethtool_stats(struct net_device *dev, | |
229 | struct ethtool_stats *stats, u64 *data) | |
230 | { | |
acbddb59 | 231 | int i, k, tmp; |
7a291083 | 232 | struct ehea_port *port = netdev_priv(dev); |
7a291083 | 233 | |
b9f2c044 | 234 | for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++) |
7a291083 | 235 | data[i] = 0; |
7a291083 JBT |
236 | i = 0; |
237 | ||
7a291083 JBT |
238 | data[i++] = port->sig_comp_iv; |
239 | data[i++] = port->port_res[0].swqe_refill_th; | |
240 | data[i++] = port->resets; | |
241 | ||
acbddb59 JBT |
242 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) |
243 | tmp += port->port_res[k].p_stats.poll_receive_errors; | |
244 | data[i++] = tmp; | |
245 | ||
246 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | |
247 | tmp += port->port_res[k].p_stats.err_tcp_cksum; | |
248 | data[i++] = tmp; | |
249 | ||
250 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | |
251 | tmp += port->port_res[k].p_stats.err_ip_cksum; | |
252 | data[i++] = tmp; | |
253 | ||
254 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | |
255 | tmp += port->port_res[k].p_stats.err_frame_crc; | |
256 | data[i++] = tmp; | |
257 | ||
258 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | |
259 | tmp += port->port_res[k].p_stats.queue_stopped; | |
260 | data[i++] = tmp; | |
261 | ||
b9564468 | 262 | for (k = 0; k < 16; k++) |
acbddb59 | 263 | data[i++] = atomic_read(&port->port_res[k].swqe_avail); |
7a291083 JBT |
264 | } |
265 | ||
1886e5d2 | 266 | static const struct ethtool_ops ehea_ethtool_ops = { |
7a291083 JBT |
267 | .get_settings = ehea_get_settings, |
268 | .get_drvinfo = ehea_get_drvinfo, | |
269 | .get_msglevel = ehea_get_msglevel, | |
270 | .set_msglevel = ehea_set_msglevel, | |
271 | .get_link = ethtool_op_get_link, | |
7a291083 | 272 | .get_strings = ehea_get_strings, |
b9f2c044 | 273 | .get_sset_count = ehea_get_sset_count, |
7a291083 | 274 | .get_ethtool_stats = ehea_get_ethtool_stats, |
7a291083 JBT |
275 | .set_settings = ehea_set_settings, |
276 | .nway_reset = ehea_nway_reset, /* Restart autonegotiation */ | |
277 | }; | |
278 | ||
279 | void ehea_set_ethtool_ops(struct net_device *netdev) | |
280 | { | |
281 | SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops); | |
282 | } |