xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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