Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge
[cascardo/linux.git] / drivers / net / ehea / ehea_ethtool.c
1 /*
2  *  linux/drivers/net/ehea/ehea_ethtool.c
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
29 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
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);
37         u32 speed;
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)) {
46                 switch (port->port_speed) {
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 */
62                 }
63                 cmd->duplex = port->full_duplex == 1 ?
64                                                      DUPLEX_FULL : DUPLEX_HALF;
65         } else {
66                 speed = ~0;
67                 cmd->duplex = -1;
68         }
69         ethtool_cmd_speed_set(cmd, speed);
70
71         cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full
72                        | SUPPORTED_100baseT_Full |  SUPPORTED_100baseT_Half
73                        | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half
74                        | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
75
76         cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg
77                          | ADVERTISED_FIBRE);
78
79         cmd->port = PORT_FIBRE;
80         cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
81
82         return 0;
83 }
84
85 static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
86 {
87         struct ehea_port *port = netdev_priv(dev);
88         int ret = 0;
89         u32 sp;
90
91         if (cmd->autoneg == AUTONEG_ENABLE) {
92                 sp = EHEA_SPEED_AUTONEG;
93                 goto doit;
94         }
95
96         switch (cmd->speed) {
97         case SPEED_10:
98                 if (cmd->duplex == DUPLEX_FULL)
99                         sp = H_SPEED_10M_F;
100                 else
101                         sp = H_SPEED_10M_H;
102                 break;
103
104         case SPEED_100:
105                 if (cmd->duplex == DUPLEX_FULL)
106                         sp = H_SPEED_100M_F;
107                 else
108                         sp = H_SPEED_100M_H;
109                 break;
110
111         case SPEED_1000:
112                 if (cmd->duplex == DUPLEX_FULL)
113                         sp = H_SPEED_1G_F;
114                 else
115                         ret = -EINVAL;
116                 break;
117
118         case SPEED_10000:
119                 if (cmd->duplex == DUPLEX_FULL)
120                         sp = H_SPEED_10G_F;
121                 else
122                         ret = -EINVAL;
123                 break;
124
125         default:
126                         ret = -EINVAL;
127                 break;
128         }
129
130         if (ret)
131                 goto out;
132 doit:
133         ret = ehea_set_portspeed(port, sp);
134
135         if (!ret)
136                 netdev_info(dev,
137                             "Port speed successfully set: %dMbps %s Duplex\n",
138                             port->port_speed,
139                             port->full_duplex == 1 ? "Full" : "Half");
140 out:
141         return ret;
142 }
143
144 static int ehea_nway_reset(struct net_device *dev)
145 {
146         struct ehea_port *port = netdev_priv(dev);
147         int ret;
148
149         ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
150
151         if (!ret)
152                 netdev_info(port->netdev,
153                             "Port speed successfully set: %dMbps %s Duplex\n",
154                             port->port_speed,
155                             port->full_duplex == 1 ? "Full" : "Half");
156         return ret;
157 }
158
159 static void ehea_get_drvinfo(struct net_device *dev,
160                                struct ethtool_drvinfo *info)
161 {
162         strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
163         strlcpy(info->version, DRV_VERSION, sizeof(info->version));
164 }
165
166 static u32 ehea_get_msglevel(struct net_device *dev)
167 {
168         struct ehea_port *port = netdev_priv(dev);
169         return port->msg_enable;
170 }
171
172 static void ehea_set_msglevel(struct net_device *dev, u32 value)
173 {
174         struct ehea_port *port = netdev_priv(dev);
175         port->msg_enable = value;
176 }
177
178 static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
179         {"sig_comp_iv"},
180         {"swqe_refill_th"},
181         {"port resets"},
182         {"Receive errors"},
183         {"TCP cksum errors"},
184         {"IP cksum errors"},
185         {"Frame cksum errors"},
186         {"num SQ stopped"},
187         {"SQ stopped"},
188         {"PR0 free_swqes"},
189         {"PR1 free_swqes"},
190         {"PR2 free_swqes"},
191         {"PR3 free_swqes"},
192         {"PR4 free_swqes"},
193         {"PR5 free_swqes"},
194         {"PR6 free_swqes"},
195         {"PR7 free_swqes"},
196         {"LRO aggregated"},
197         {"LRO flushed"},
198         {"LRO no_desc"},
199 };
200
201 static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
202 {
203         if (stringset == ETH_SS_STATS) {
204                 memcpy(data, &ehea_ethtool_stats_keys,
205                        sizeof(ehea_ethtool_stats_keys));
206         }
207 }
208
209 static int ehea_get_sset_count(struct net_device *dev, int sset)
210 {
211         switch (sset) {
212         case ETH_SS_STATS:
213                 return ARRAY_SIZE(ehea_ethtool_stats_keys);
214         default:
215                 return -EOPNOTSUPP;
216         }
217 }
218
219 static void ehea_get_ethtool_stats(struct net_device *dev,
220                                      struct ethtool_stats *stats, u64 *data)
221 {
222         int i, k, tmp;
223         struct ehea_port *port = netdev_priv(dev);
224
225         for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)
226                 data[i] = 0;
227         i = 0;
228
229         data[i++] = port->sig_comp_iv;
230         data[i++] = port->port_res[0].swqe_refill_th;
231         data[i++] = port->resets;
232
233         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
234                 tmp += port->port_res[k].p_stats.poll_receive_errors;
235         data[i++] = tmp;
236
237         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
238                 tmp += port->port_res[k].p_stats.err_tcp_cksum;
239         data[i++] = tmp;
240
241         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
242                 tmp += port->port_res[k].p_stats.err_ip_cksum;
243         data[i++] = tmp;
244
245         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
246                 tmp += port->port_res[k].p_stats.err_frame_crc;
247         data[i++] = tmp;
248
249         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
250                 tmp += port->port_res[k].p_stats.queue_stopped;
251         data[i++] = tmp;
252
253         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
254                 tmp |= port->port_res[k].queue_stopped;
255         data[i++] = tmp;
256
257         for (k = 0; k < 8; k++)
258                 data[i++] = atomic_read(&port->port_res[k].swqe_avail);
259
260         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
261                 tmp |= port->port_res[k].lro_mgr.stats.aggregated;
262         data[i++] = tmp;
263
264         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
265                 tmp |= port->port_res[k].lro_mgr.stats.flushed;
266         data[i++] = tmp;
267
268         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
269                 tmp |= port->port_res[k].lro_mgr.stats.no_desc;
270         data[i++] = tmp;
271
272 }
273
274 const struct ethtool_ops ehea_ethtool_ops = {
275         .get_settings = ehea_get_settings,
276         .get_drvinfo = ehea_get_drvinfo,
277         .get_msglevel = ehea_get_msglevel,
278         .set_msglevel = ehea_set_msglevel,
279         .get_link = ethtool_op_get_link,
280         .get_strings = ehea_get_strings,
281         .get_sset_count = ehea_get_sset_count,
282         .get_ethtool_stats = ehea_get_ethtool_stats,
283         .set_settings = ehea_set_settings,
284         .nway_reset = ehea_nway_reset,          /* Restart autonegotiation */
285 };
286
287 void ehea_set_ethtool_ops(struct net_device *netdev)
288 {
289         SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops);
290 }