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