xref: /linux/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell Octeon EP (EndPoint) VF Ethernet Driver
3  *
4  * Copyright (C) 2020 Marvell.
5  *
6  */
7 
8 #include <linux/pci.h>
9 #include <linux/netdevice.h>
10 #include <linux/ethtool.h>
11 
12 #include "octep_vf_config.h"
13 #include "octep_vf_main.h"
14 
15 static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = {
16 	"rx_alloc_errors",
17 	"tx_busy_errors",
18 	"tx_hw_pkts",
19 	"tx_hw_octs",
20 	"tx_hw_bcast",
21 	"tx_hw_mcast",
22 	"rx_hw_pkts",
23 	"rx_hw_bytes",
24 	"rx_hw_bcast",
25 	"rx_dropped_bytes_fifo_full",
26 };
27 
28 #define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN)
29 
30 static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = {
31 	"tx_packets_posted[Q-%u]",
32 	"tx_packets_completed[Q-%u]",
33 	"tx_bytes[Q-%u]",
34 	"tx_busy[Q-%u]",
35 };
36 
37 #define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN)
38 
39 static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = {
40 	"rx_packets[Q-%u]",
41 	"rx_bytes[Q-%u]",
42 	"rx_alloc_errors[Q-%u]",
43 };
44 
45 #define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN)
46 
octep_vf_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)47 static void octep_vf_get_drvinfo(struct net_device *netdev,
48 				 struct ethtool_drvinfo *info)
49 {
50 	struct octep_vf_device *oct = netdev_priv(netdev);
51 
52 	strscpy(info->driver, OCTEP_VF_DRV_NAME, sizeof(info->driver));
53 	strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info));
54 }
55 
octep_vf_get_strings(struct net_device * netdev,u32 stringset,u8 * data)56 static void octep_vf_get_strings(struct net_device *netdev,
57 				 u32 stringset, u8 *data)
58 {
59 	struct octep_vf_device *oct = netdev_priv(netdev);
60 	u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
61 	char *strings = (char *)data;
62 	int i, j;
63 
64 	switch (stringset) {
65 	case ETH_SS_STATS:
66 		for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) {
67 			snprintf(strings, ETH_GSTRING_LEN,
68 				 octep_vf_gstrings_global_stats[i]);
69 			strings += ETH_GSTRING_LEN;
70 		}
71 
72 		for (i = 0; i < num_queues; i++) {
73 			for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) {
74 				snprintf(strings, ETH_GSTRING_LEN,
75 					 octep_vf_gstrings_tx_q_stats[j], i);
76 				strings += ETH_GSTRING_LEN;
77 			}
78 		}
79 
80 		for (i = 0; i < num_queues; i++) {
81 			for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) {
82 				snprintf(strings, ETH_GSTRING_LEN,
83 					 octep_vf_gstrings_rx_q_stats[j], i);
84 				strings += ETH_GSTRING_LEN;
85 			}
86 		}
87 		break;
88 	default:
89 		break;
90 	}
91 }
92 
octep_vf_get_sset_count(struct net_device * netdev,int sset)93 static int octep_vf_get_sset_count(struct net_device *netdev, int sset)
94 {
95 	struct octep_vf_device *oct = netdev_priv(netdev);
96 	u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
97 
98 	switch (sset) {
99 	case ETH_SS_STATS:
100 		return OCTEP_VF_GLOBAL_STATS_CNT + (num_queues *
101 		       (OCTEP_VF_TX_Q_STATS_CNT + OCTEP_VF_RX_Q_STATS_CNT));
102 		break;
103 	default:
104 		return -EOPNOTSUPP;
105 	}
106 }
107 
octep_vf_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)108 static void octep_vf_get_ethtool_stats(struct net_device *netdev,
109 				       struct ethtool_stats *stats, u64 *data)
110 {
111 	struct octep_vf_device *oct = netdev_priv(netdev);
112 	struct octep_vf_iface_tx_stats *iface_tx_stats;
113 	struct octep_vf_iface_rx_stats *iface_rx_stats;
114 	u64 rx_alloc_errors, tx_busy_errors;
115 	int q, i;
116 
117 	rx_alloc_errors = 0;
118 	tx_busy_errors = 0;
119 
120 	octep_vf_get_if_stats(oct);
121 	iface_tx_stats = &oct->iface_tx_stats;
122 	iface_rx_stats = &oct->iface_rx_stats;
123 
124 	for (q = 0; q < oct->num_oqs; q++) {
125 		struct octep_vf_iq *iq = oct->iq[q];
126 		struct octep_vf_oq *oq = oct->oq[q];
127 
128 		tx_busy_errors += iq->stats.tx_busy;
129 		rx_alloc_errors += oq->stats.alloc_failures;
130 	}
131 	i = 0;
132 	data[i++] = rx_alloc_errors;
133 	data[i++] = tx_busy_errors;
134 	data[i++] = iface_tx_stats->pkts;
135 	data[i++] = iface_tx_stats->octs;
136 	data[i++] = iface_tx_stats->bcst;
137 	data[i++] = iface_tx_stats->mcst;
138 	data[i++] = iface_rx_stats->pkts;
139 	data[i++] = iface_rx_stats->octets;
140 	data[i++] = iface_rx_stats->bcast_pkts;
141 	data[i++] = iface_rx_stats->dropped_octets_fifo_full;
142 
143 	/* Per Tx Queue stats */
144 	for (q = 0; q < oct->num_iqs; q++) {
145 		struct octep_vf_iq *iq = oct->iq[q];
146 
147 		data[i++] = iq->stats.instr_posted;
148 		data[i++] = iq->stats.instr_completed;
149 		data[i++] = iq->stats.bytes_sent;
150 		data[i++] = iq->stats.tx_busy;
151 	}
152 
153 	/* Per Rx Queue stats */
154 	for (q = 0; q < oct->num_oqs; q++) {
155 		struct octep_vf_oq *oq = oct->oq[q];
156 
157 		data[i++] = oq->stats.packets;
158 		data[i++] = oq->stats.bytes;
159 		data[i++] = oq->stats.alloc_failures;
160 	}
161 }
162 
163 #define OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(octep_vf_speeds, ksettings, name) \
164 { \
165 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_T)) \
166 		ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \
167 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_R)) \
168 		ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \
169 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_CR)) \
170 		ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \
171 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_KR)) \
172 		ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \
173 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_LR)) \
174 		ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \
175 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_SR)) \
176 		ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \
177 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_CR)) \
178 		ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \
179 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_KR)) \
180 		ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \
181 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_SR)) \
182 		ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \
183 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_CR4)) \
184 		ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \
185 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_KR4)) \
186 		ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \
187 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_LR4)) \
188 		ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \
189 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_SR4)) \
190 		ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \
191 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR2)) \
192 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \
193 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR2)) \
194 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \
195 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR2)) \
196 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \
197 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR)) \
198 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \
199 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR)) \
200 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \
201 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_LR)) \
202 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \
203 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR)) \
204 		ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \
205 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_CR4)) \
206 		ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \
207 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_KR4)) \
208 		ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \
209 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_LR4)) \
210 		ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \
211 	if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_SR4)) \
212 		ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \
213 }
214 
octep_vf_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)215 static int octep_vf_get_link_ksettings(struct net_device *netdev,
216 				       struct ethtool_link_ksettings *cmd)
217 {
218 	struct octep_vf_device *oct = netdev_priv(netdev);
219 	struct octep_vf_iface_link_info *link_info;
220 	u32 advertised_modes, supported_modes;
221 
222 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
223 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
224 
225 	octep_vf_get_link_info(oct);
226 
227 	advertised_modes = oct->link_info.advertised_modes;
228 	supported_modes = oct->link_info.supported_modes;
229 	link_info = &oct->link_info;
230 
231 	OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported);
232 	OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);
233 
234 	if (link_info->autoneg) {
235 		if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED)
236 			ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
237 		if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED) {
238 			ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
239 			cmd->base.autoneg = AUTONEG_ENABLE;
240 		} else {
241 			cmd->base.autoneg = AUTONEG_DISABLE;
242 		}
243 	} else {
244 		cmd->base.autoneg = AUTONEG_DISABLE;
245 	}
246 
247 	cmd->base.port = PORT_FIBRE;
248 	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
249 	ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
250 
251 	if (netif_carrier_ok(netdev)) {
252 		cmd->base.speed = link_info->speed;
253 		cmd->base.duplex = DUPLEX_FULL;
254 	} else {
255 		cmd->base.speed = SPEED_UNKNOWN;
256 		cmd->base.duplex = DUPLEX_UNKNOWN;
257 	}
258 	return 0;
259 }
260 
261 static const struct ethtool_ops octep_vf_ethtool_ops = {
262 	.get_drvinfo = octep_vf_get_drvinfo,
263 	.get_link = ethtool_op_get_link,
264 	.get_strings = octep_vf_get_strings,
265 	.get_sset_count = octep_vf_get_sset_count,
266 	.get_ethtool_stats = octep_vf_get_ethtool_stats,
267 	.get_link_ksettings = octep_vf_get_link_ksettings,
268 };
269 
octep_vf_set_ethtool_ops(struct net_device * netdev)270 void octep_vf_set_ethtool_ops(struct net_device *netdev)
271 {
272 	netdev->ethtool_ops = &octep_vf_ethtool_ops;
273 }
274