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 < OCTEP_VF_MAX_QUEUES; q++) {
125 tx_busy_errors += oct->stats_iq[q].tx_busy;
126 rx_alloc_errors += oct->stats_oq[q].alloc_failures;
127 }
128 i = 0;
129 data[i++] = rx_alloc_errors;
130 data[i++] = tx_busy_errors;
131 data[i++] = iface_tx_stats->pkts;
132 data[i++] = iface_tx_stats->octs;
133 data[i++] = iface_tx_stats->bcst;
134 data[i++] = iface_tx_stats->mcst;
135 data[i++] = iface_rx_stats->pkts;
136 data[i++] = iface_rx_stats->octets;
137 data[i++] = iface_rx_stats->bcast_pkts;
138 data[i++] = iface_rx_stats->dropped_octets_fifo_full;
139
140 /* Per Tx Queue stats */
141 for (q = 0; q < OCTEP_VF_MAX_QUEUES; q++) {
142 data[i++] = oct->stats_iq[q].instr_posted;
143 data[i++] = oct->stats_iq[q].instr_completed;
144 data[i++] = oct->stats_iq[q].bytes_sent;
145 data[i++] = oct->stats_iq[q].tx_busy;
146 }
147
148 /* Per Rx Queue stats */
149 for (q = 0; q < oct->num_oqs; q++) {
150 data[i++] = oct->stats_oq[q].packets;
151 data[i++] = oct->stats_oq[q].bytes;
152 data[i++] = oct->stats_oq[q].alloc_failures;
153 }
154 }
155
156 #define OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(octep_vf_speeds, ksettings, name) \
157 { \
158 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_T)) \
159 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \
160 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_R)) \
161 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \
162 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_CR)) \
163 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \
164 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_KR)) \
165 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \
166 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_LR)) \
167 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \
168 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_SR)) \
169 ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \
170 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_CR)) \
171 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \
172 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_KR)) \
173 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \
174 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_SR)) \
175 ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \
176 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_CR4)) \
177 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \
178 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_KR4)) \
179 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \
180 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_LR4)) \
181 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \
182 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_SR4)) \
183 ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \
184 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR2)) \
185 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \
186 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR2)) \
187 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \
188 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR2)) \
189 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \
190 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR)) \
191 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \
192 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR)) \
193 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \
194 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_LR)) \
195 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \
196 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR)) \
197 ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \
198 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_CR4)) \
199 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \
200 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_KR4)) \
201 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \
202 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_LR4)) \
203 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \
204 if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_SR4)) \
205 ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \
206 }
207
octep_vf_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)208 static int octep_vf_get_link_ksettings(struct net_device *netdev,
209 struct ethtool_link_ksettings *cmd)
210 {
211 struct octep_vf_device *oct = netdev_priv(netdev);
212 struct octep_vf_iface_link_info *link_info;
213 u32 advertised_modes, supported_modes;
214
215 ethtool_link_ksettings_zero_link_mode(cmd, supported);
216 ethtool_link_ksettings_zero_link_mode(cmd, advertising);
217
218 octep_vf_get_link_info(oct);
219
220 advertised_modes = oct->link_info.advertised_modes;
221 supported_modes = oct->link_info.supported_modes;
222 link_info = &oct->link_info;
223
224 OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported);
225 OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising);
226
227 if (link_info->autoneg) {
228 if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED)
229 ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
230 if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED) {
231 ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
232 cmd->base.autoneg = AUTONEG_ENABLE;
233 } else {
234 cmd->base.autoneg = AUTONEG_DISABLE;
235 }
236 } else {
237 cmd->base.autoneg = AUTONEG_DISABLE;
238 }
239
240 cmd->base.port = PORT_FIBRE;
241 ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
242 ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
243
244 if (netif_carrier_ok(netdev)) {
245 cmd->base.speed = link_info->speed;
246 cmd->base.duplex = DUPLEX_FULL;
247 } else {
248 cmd->base.speed = SPEED_UNKNOWN;
249 cmd->base.duplex = DUPLEX_UNKNOWN;
250 }
251 return 0;
252 }
253
254 static const struct ethtool_ops octep_vf_ethtool_ops = {
255 .get_drvinfo = octep_vf_get_drvinfo,
256 .get_link = ethtool_op_get_link,
257 .get_strings = octep_vf_get_strings,
258 .get_sset_count = octep_vf_get_sset_count,
259 .get_ethtool_stats = octep_vf_get_ethtool_stats,
260 .get_link_ksettings = octep_vf_get_link_ksettings,
261 };
262
octep_vf_set_ethtool_ops(struct net_device * netdev)263 void octep_vf_set_ethtool_ops(struct net_device *netdev)
264 {
265 netdev->ethtool_ops = &octep_vf_ethtool_ops;
266 }
267