GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / net / ethernet / ibm / ehea / ehea_ethtool.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  linux/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
4  *
5  *  eHEA ethernet device driver for IBM eServer System p
6  *
7  *  (C) Copyright IBM Corp. 2006
8  *
9  *  Authors:
10  *       Christoph Raisch <raisch@de.ibm.com>
11  *       Jan-Bernd Themann <themann@de.ibm.com>
12  *       Thomas Klein <tklein@de.ibm.com>
13  */
14
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17 #include "ehea.h"
18 #include "ehea_phyp.h"
19
20 static int ehea_get_link_ksettings(struct net_device *dev,
21                                    struct ethtool_link_ksettings *cmd)
22 {
23         struct ehea_port *port = netdev_priv(dev);
24         u32 supported, advertising;
25         u32 speed;
26         int ret;
27
28         ret = ehea_sense_port_attr(port);
29
30         if (ret)
31                 return ret;
32
33         if (netif_carrier_ok(dev)) {
34                 switch (port->port_speed) {
35                 case EHEA_SPEED_10M:
36                         speed = SPEED_10;
37                         break;
38                 case EHEA_SPEED_100M:
39                         speed = SPEED_100;
40                         break;
41                 case EHEA_SPEED_1G:
42                         speed = SPEED_1000;
43                         break;
44                 case EHEA_SPEED_10G:
45                         speed = SPEED_10000;
46                         break;
47                 default:
48                         speed = -1;
49                         break; /* BUG */
50                 }
51                 cmd->base.duplex = port->full_duplex == 1 ?
52                                                      DUPLEX_FULL : DUPLEX_HALF;
53         } else {
54                 speed = SPEED_UNKNOWN;
55                 cmd->base.duplex = DUPLEX_UNKNOWN;
56         }
57         cmd->base.speed = speed;
58
59         if (cmd->base.speed == SPEED_10000) {
60                 supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
61                 advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
62                 cmd->base.port = PORT_FIBRE;
63         } else {
64                 supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full
65                                | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full
66                                | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg
67                                | SUPPORTED_TP);
68                 advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg
69                                  | ADVERTISED_TP);
70                 cmd->base.port = PORT_TP;
71         }
72
73         cmd->base.autoneg = port->autoneg == 1 ?
74                 AUTONEG_ENABLE : AUTONEG_DISABLE;
75
76         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
77                                                 supported);
78         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
79                                                 advertising);
80
81         return 0;
82 }
83
84 static int ehea_set_link_ksettings(struct net_device *dev,
85                                    const struct ethtool_link_ksettings *cmd)
86 {
87         struct ehea_port *port = netdev_priv(dev);
88         int ret = 0;
89         u32 sp;
90
91         if (cmd->base.autoneg == AUTONEG_ENABLE) {
92                 sp = EHEA_SPEED_AUTONEG;
93                 goto doit;
94         }
95
96         switch (cmd->base.speed) {
97         case SPEED_10:
98                 if (cmd->base.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->base.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->base.duplex == DUPLEX_FULL)
113                         sp = H_SPEED_1G_F;
114                 else
115                         ret = -EINVAL;
116                 break;
117
118         case SPEED_10000:
119                 if (cmd->base.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 const 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         {"PR0 free_swqes"},
188         {"PR1 free_swqes"},
189         {"PR2 free_swqes"},
190         {"PR3 free_swqes"},
191         {"PR4 free_swqes"},
192         {"PR5 free_swqes"},
193         {"PR6 free_swqes"},
194         {"PR7 free_swqes"},
195         {"PR8 free_swqes"},
196         {"PR9 free_swqes"},
197         {"PR10 free_swqes"},
198         {"PR11 free_swqes"},
199         {"PR12 free_swqes"},
200         {"PR13 free_swqes"},
201         {"PR14 free_swqes"},
202         {"PR15 free_swqes"},
203 };
204
205 static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
206 {
207         if (stringset == ETH_SS_STATS) {
208                 memcpy(data, &ehea_ethtool_stats_keys,
209                        sizeof(ehea_ethtool_stats_keys));
210         }
211 }
212
213 static int ehea_get_sset_count(struct net_device *dev, int sset)
214 {
215         switch (sset) {
216         case ETH_SS_STATS:
217                 return ARRAY_SIZE(ehea_ethtool_stats_keys);
218         default:
219                 return -EOPNOTSUPP;
220         }
221 }
222
223 static void ehea_get_ethtool_stats(struct net_device *dev,
224                                      struct ethtool_stats *stats, u64 *data)
225 {
226         int i, k, tmp;
227         struct ehea_port *port = netdev_priv(dev);
228
229         for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)
230                 data[i] = 0;
231         i = 0;
232
233         data[i++] = port->sig_comp_iv;
234         data[i++] = port->port_res[0].swqe_refill_th;
235         data[i++] = port->resets;
236
237         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
238                 tmp += port->port_res[k].p_stats.poll_receive_errors;
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_tcp_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_ip_cksum;
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.err_frame_crc;
251         data[i++] = tmp;
252
253         for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
254                 tmp += port->port_res[k].p_stats.queue_stopped;
255         data[i++] = tmp;
256
257         for (k = 0; k < 16; k++)
258                 data[i++] = atomic_read(&port->port_res[k].swqe_avail);
259 }
260
261 static const struct ethtool_ops ehea_ethtool_ops = {
262         .get_drvinfo = ehea_get_drvinfo,
263         .get_msglevel = ehea_get_msglevel,
264         .set_msglevel = ehea_set_msglevel,
265         .get_link = ethtool_op_get_link,
266         .get_strings = ehea_get_strings,
267         .get_sset_count = ehea_get_sset_count,
268         .get_ethtool_stats = ehea_get_ethtool_stats,
269         .nway_reset = ehea_nway_reset,          /* Restart autonegotiation */
270         .get_link_ksettings = ehea_get_link_ksettings,
271         .set_link_ksettings = ehea_set_link_ksettings,
272 };
273
274 void ehea_set_ethtool_ops(struct net_device *netdev)
275 {
276         netdev->ethtool_ops = &ehea_ethtool_ops;
277 }