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