History

net/funeth: ethtool operations

Add ethtool operations, primarily related to queues and ports, as well as device statistics.

Dimitris Michailidis committed 4 years ago

Commit 21c5ea91 parent ee6373d2 files · +1259 −0Browse files

Unified · Split

2 files
  1. drivers/net/ethernet/fungible/funeth/fun_port.h +97 −0
  2. drivers/net/ethernet/fungible/funeth/funeth_ethtool.c +1162 −0
drivers/net/ethernet/fungible/funeth/fun_port.h+97−0
@@ -0,0 +1,97 @@
1+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
2+
3+#ifndef _FUN_PORT_H
4+#define _FUN_PORT_H
5+
6+enum port_mac_rx_stats {
7+ PORT_MAC_RX_etherStatsOctets = 0x0,
8+ PORT_MAC_RX_OctetsReceivedOK = 0x1,
9+ PORT_MAC_RX_aAlignmentErrors = 0x2,
10+ PORT_MAC_RX_aPAUSEMACCtrlFramesReceived = 0x3,
11+ PORT_MAC_RX_aFrameTooLongErrors = 0x4,
12+ PORT_MAC_RX_aInRangeLengthErrors = 0x5,
13+ PORT_MAC_RX_aFramesReceivedOK = 0x6,
14+ PORT_MAC_RX_aFrameCheckSequenceErrors = 0x7,
15+ PORT_MAC_RX_VLANReceivedOK = 0x8,
16+ PORT_MAC_RX_ifInErrors = 0x9,
17+ PORT_MAC_RX_ifInUcastPkts = 0xa,
18+ PORT_MAC_RX_ifInMulticastPkts = 0xb,
19+ PORT_MAC_RX_ifInBroadcastPkts = 0xc,
20+ PORT_MAC_RX_etherStatsDropEvents = 0xd,
21+ PORT_MAC_RX_etherStatsPkts = 0xe,
22+ PORT_MAC_RX_etherStatsUndersizePkts = 0xf,
23+ PORT_MAC_RX_etherStatsPkts64Octets = 0x10,
24+ PORT_MAC_RX_etherStatsPkts65to127Octets = 0x11,
25+ PORT_MAC_RX_etherStatsPkts128to255Octets = 0x12,
26+ PORT_MAC_RX_etherStatsPkts256to511Octets = 0x13,
27+ PORT_MAC_RX_etherStatsPkts512to1023Octets = 0x14,
28+ PORT_MAC_RX_etherStatsPkts1024to1518Octets = 0x15,
29+ PORT_MAC_RX_etherStatsPkts1519toMaxOctets = 0x16,
30+ PORT_MAC_RX_etherStatsOversizePkts = 0x17,
31+ PORT_MAC_RX_etherStatsJabbers = 0x18,
32+ PORT_MAC_RX_etherStatsFragments = 0x19,
33+ PORT_MAC_RX_CBFCPAUSEFramesReceived_0 = 0x1a,
34+ PORT_MAC_RX_CBFCPAUSEFramesReceived_1 = 0x1b,
35+ PORT_MAC_RX_CBFCPAUSEFramesReceived_2 = 0x1c,
36+ PORT_MAC_RX_CBFCPAUSEFramesReceived_3 = 0x1d,
37+ PORT_MAC_RX_CBFCPAUSEFramesReceived_4 = 0x1e,
38+ PORT_MAC_RX_CBFCPAUSEFramesReceived_5 = 0x1f,
39+ PORT_MAC_RX_CBFCPAUSEFramesReceived_6 = 0x20,
40+ PORT_MAC_RX_CBFCPAUSEFramesReceived_7 = 0x21,
41+ PORT_MAC_RX_CBFCPAUSEFramesReceived_8 = 0x22,
42+ PORT_MAC_RX_CBFCPAUSEFramesReceived_9 = 0x23,
43+ PORT_MAC_RX_CBFCPAUSEFramesReceived_10 = 0x24,
44+ PORT_MAC_RX_CBFCPAUSEFramesReceived_11 = 0x25,
45+ PORT_MAC_RX_CBFCPAUSEFramesReceived_12 = 0x26,
46+ PORT_MAC_RX_CBFCPAUSEFramesReceived_13 = 0x27,
47+ PORT_MAC_RX_CBFCPAUSEFramesReceived_14 = 0x28,
48+ PORT_MAC_RX_CBFCPAUSEFramesReceived_15 = 0x29,
49+ PORT_MAC_RX_MACControlFramesReceived = 0x2a,
50+ PORT_MAC_RX_STATS_MAX = 0x2b,
51+};
52+
53+enum port_mac_tx_stats {
54+ PORT_MAC_TX_etherStatsOctets = 0x0,
55+ PORT_MAC_TX_OctetsTransmittedOK = 0x1,
56+ PORT_MAC_TX_aPAUSEMACCtrlFramesTransmitted = 0x2,
57+ PORT_MAC_TX_aFramesTransmittedOK = 0x3,
58+ PORT_MAC_TX_VLANTransmittedOK = 0x4,
59+ PORT_MAC_TX_ifOutErrors = 0x5,
60+ PORT_MAC_TX_ifOutUcastPkts = 0x6,
61+ PORT_MAC_TX_ifOutMulticastPkts = 0x7,
62+ PORT_MAC_TX_ifOutBroadcastPkts = 0x8,
63+ PORT_MAC_TX_etherStatsPkts64Octets = 0x9,
64+ PORT_MAC_TX_etherStatsPkts65to127Octets = 0xa,
65+ PORT_MAC_TX_etherStatsPkts128to255Octets = 0xb,
66+ PORT_MAC_TX_etherStatsPkts256to511Octets = 0xc,
67+ PORT_MAC_TX_etherStatsPkts512to1023Octets = 0xd,
68+ PORT_MAC_TX_etherStatsPkts1024to1518Octets = 0xe,
69+ PORT_MAC_TX_etherStatsPkts1519toMaxOctets = 0xf,
70+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_0 = 0x10,
71+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_1 = 0x11,
72+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_2 = 0x12,
73+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_3 = 0x13,
74+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_4 = 0x14,
75+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_5 = 0x15,
76+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_6 = 0x16,
77+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_7 = 0x17,
78+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_8 = 0x18,
79+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_9 = 0x19,
80+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_10 = 0x1a,
81+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_11 = 0x1b,
82+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_12 = 0x1c,
83+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_13 = 0x1d,
84+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_14 = 0x1e,
85+ PORT_MAC_TX_CBFCPAUSEFramesTransmitted_15 = 0x1f,
86+ PORT_MAC_TX_MACControlFramesTransmitted = 0x20,
87+ PORT_MAC_TX_etherStatsPkts = 0x21,
88+ PORT_MAC_TX_STATS_MAX = 0x22,
89+};
90+
91+enum port_mac_fec_stats {
92+ PORT_MAC_FEC_Correctable = 0x0,
93+ PORT_MAC_FEC_Uncorrectable = 0x1,
94+ PORT_MAC_FEC_STATS_MAX = 0x2,
95+};
96+
97+#endif /* _FUN_PORT_H */
drivers/net/ethernet/fungible/funeth/funeth_ethtool.c+1162−0
@@ -0,0 +1,1162 @@
1+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2+
3+#include <linux/ethtool.h>
4+#include <linux/linkmode.h>
5+#include <linux/netdevice.h>
6+#include <linux/nvme.h>
7+#include <linux/io.h>
8+#include <linux/io-64-nonatomic-lo-hi.h>
9+#include <linux/pci.h>
10+#include <linux/rtnetlink.h>
11+#include "funeth.h"
12+#include "fun_port.h"
13+#include "funeth_txrx.h"
14+
15+/* Min queue depth. The smallest power-of-2 supporting jumbo frames with 4K
16+ * pages is 8. Require it for all types of queues though some could work with
17+ * fewer entries.
18+ */
19+#define FUNETH_MIN_QDEPTH 8
20+
21+static const char mac_tx_stat_names[][ETH_GSTRING_LEN] = {
22+ "mac_tx_octets_total",
23+ "mac_tx_frames_total",
24+ "mac_tx_vlan_frames_ok",
25+ "mac_tx_unicast_frames",
26+ "mac_tx_multicast_frames",
27+ "mac_tx_broadcast_frames",
28+ "mac_tx_errors",
29+ "mac_tx_CBFCPAUSE0",
30+ "mac_tx_CBFCPAUSE1",
31+ "mac_tx_CBFCPAUSE2",
32+ "mac_tx_CBFCPAUSE3",
33+ "mac_tx_CBFCPAUSE4",
34+ "mac_tx_CBFCPAUSE5",
35+ "mac_tx_CBFCPAUSE6",
36+ "mac_tx_CBFCPAUSE7",
37+ "mac_tx_CBFCPAUSE8",
38+ "mac_tx_CBFCPAUSE9",
39+ "mac_tx_CBFCPAUSE10",
40+ "mac_tx_CBFCPAUSE11",
41+ "mac_tx_CBFCPAUSE12",
42+ "mac_tx_CBFCPAUSE13",
43+ "mac_tx_CBFCPAUSE14",
44+ "mac_tx_CBFCPAUSE15",
45+};
46+
47+static const char mac_rx_stat_names[][ETH_GSTRING_LEN] = {
48+ "mac_rx_octets_total",
49+ "mac_rx_frames_total",
50+ "mac_rx_VLAN_frames_ok",
51+ "mac_rx_unicast_frames",
52+ "mac_rx_multicast_frames",
53+ "mac_rx_broadcast_frames",
54+ "mac_rx_drop_events",
55+ "mac_rx_errors",
56+ "mac_rx_alignment_errors",
57+ "mac_rx_CBFCPAUSE0",
58+ "mac_rx_CBFCPAUSE1",
59+ "mac_rx_CBFCPAUSE2",
60+ "mac_rx_CBFCPAUSE3",
61+ "mac_rx_CBFCPAUSE4",
62+ "mac_rx_CBFCPAUSE5",
63+ "mac_rx_CBFCPAUSE6",
64+ "mac_rx_CBFCPAUSE7",
65+ "mac_rx_CBFCPAUSE8",
66+ "mac_rx_CBFCPAUSE9",
67+ "mac_rx_CBFCPAUSE10",
68+ "mac_rx_CBFCPAUSE11",
69+ "mac_rx_CBFCPAUSE12",
70+ "mac_rx_CBFCPAUSE13",
71+ "mac_rx_CBFCPAUSE14",
72+ "mac_rx_CBFCPAUSE15",
73+};
74+
75+static const char * const txq_stat_names[] = {
76+ "tx_pkts",
77+ "tx_bytes",
78+ "tx_cso",
79+ "tx_tso",
80+ "tx_encapsulated_tso",
81+ "tx_more",
82+ "tx_queue_stops",
83+ "tx_queue_restarts",
84+ "tx_mapping_errors",
85+ "tx_tls_encrypted_packets",
86+ "tx_tls_encrypted_bytes",
87+ "tx_tls_ooo",
88+ "tx_tls_drop_no_sync_data",
89+};
90+
91+static const char * const xdpq_stat_names[] = {
92+ "tx_xdp_pkts",
93+ "tx_xdp_bytes",
94+ "tx_xdp_full",
95+ "tx_xdp_mapping_errors",
96+};
97+
98+static const char * const rxq_stat_names[] = {
99+ "rx_pkts",
100+ "rx_bytes",
101+ "rx_cso",
102+ "gro_pkts",
103+ "gro_merged",
104+ "rx_xdp_tx",
105+ "rx_xdp_redir",
106+ "rx_xdp_drops",
107+ "rx_buffers",
108+ "rx_page_allocs",
109+ "rx_drops",
110+ "rx_budget_exhausted",
111+ "rx_mapping_errors",
112+};
113+
114+static const char * const tls_stat_names[] = {
115+ "tx_tls_ctx",
116+ "tx_tls_del",
117+ "tx_tls_resync",
118+};
119+
120+static void fun_link_modes_to_ethtool(u64 modes,
121+ unsigned long *ethtool_modes_map)
122+{
123+#define ADD_LINK_MODE(mode) \
124+ __set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, ethtool_modes_map)
125+
126+ if (modes & FUN_PORT_CAP_AUTONEG)
127+ ADD_LINK_MODE(Autoneg);
128+ if (modes & FUN_PORT_CAP_1000_X)
129+ ADD_LINK_MODE(1000baseX_Full);
130+ if (modes & FUN_PORT_CAP_10G_R) {
131+ ADD_LINK_MODE(10000baseCR_Full);
132+ ADD_LINK_MODE(10000baseSR_Full);
133+ ADD_LINK_MODE(10000baseLR_Full);
134+ ADD_LINK_MODE(10000baseER_Full);
135+ }
136+ if (modes & FUN_PORT_CAP_25G_R) {
137+ ADD_LINK_MODE(25000baseCR_Full);
138+ ADD_LINK_MODE(25000baseSR_Full);
139+ }
140+ if (modes & FUN_PORT_CAP_40G_R4) {
141+ ADD_LINK_MODE(40000baseCR4_Full);
142+ ADD_LINK_MODE(40000baseSR4_Full);
143+ ADD_LINK_MODE(40000baseLR4_Full);
144+ }
145+ if (modes & FUN_PORT_CAP_50G_R2) {
146+ ADD_LINK_MODE(50000baseCR2_Full);
147+ ADD_LINK_MODE(50000baseSR2_Full);
148+ }
149+ if (modes & FUN_PORT_CAP_50G_R) {
150+ ADD_LINK_MODE(50000baseCR_Full);
151+ ADD_LINK_MODE(50000baseSR_Full);
152+ ADD_LINK_MODE(50000baseLR_ER_FR_Full);
153+ }
154+ if (modes & FUN_PORT_CAP_100G_R4) {
155+ ADD_LINK_MODE(100000baseCR4_Full);
156+ ADD_LINK_MODE(100000baseSR4_Full);
157+ ADD_LINK_MODE(100000baseLR4_ER4_Full);
158+ }
159+ if (modes & FUN_PORT_CAP_100G_R2) {
160+ ADD_LINK_MODE(100000baseCR2_Full);
161+ ADD_LINK_MODE(100000baseSR2_Full);
162+ ADD_LINK_MODE(100000baseLR2_ER2_FR2_Full);
163+ }
164+ if (modes & FUN_PORT_CAP_FEC_NONE)
165+ ADD_LINK_MODE(FEC_NONE);
166+ if (modes & FUN_PORT_CAP_FEC_FC)
167+ ADD_LINK_MODE(FEC_BASER);
168+ if (modes & FUN_PORT_CAP_FEC_RS)
169+ ADD_LINK_MODE(FEC_RS);
170+ if (modes & FUN_PORT_CAP_RX_PAUSE)
171+ ADD_LINK_MODE(Pause);
172+
173+#undef ADD_LINK_MODE
174+}
175+
176+static void set_asym_pause(u64 advertising, struct ethtool_link_ksettings *ks)
177+{
178+ bool rx_pause, tx_pause;
179+
180+ rx_pause = advertising & FUN_PORT_CAP_RX_PAUSE;
181+ tx_pause = advertising & FUN_PORT_CAP_TX_PAUSE;
182+ if (tx_pause ^ rx_pause)
183+ ethtool_link_ksettings_add_link_mode(ks, advertising,
184+ Asym_Pause);
185+}
186+
187+static unsigned int fun_port_type(unsigned int xcvr)
188+{
189+ if (!xcvr)
190+ return PORT_NONE;
191+
192+ switch (xcvr & 7) {
193+ case FUN_XCVR_BASET:
194+ return PORT_TP;
195+ case FUN_XCVR_CU:
196+ return PORT_DA;
197+ default:
198+ return PORT_FIBRE;
199+ }
200+}
201+
202+static int fun_get_link_ksettings(struct net_device *netdev,
203+ struct ethtool_link_ksettings *ks)
204+{
205+ const struct funeth_priv *fp = netdev_priv(netdev);
206+ unsigned int seq, speed, xcvr;
207+ u64 lp_advertising;
208+ bool link_up;
209+
210+ ethtool_link_ksettings_zero_link_mode(ks, supported);
211+ ethtool_link_ksettings_zero_link_mode(ks, advertising);
212+ ethtool_link_ksettings_zero_link_mode(ks, lp_advertising);
213+
214+ /* Link settings change asynchronously, take a consistent snapshot */
215+ do {
216+ seq = read_seqcount_begin(&fp->link_seq);
217+ link_up = netif_carrier_ok(netdev);
218+ speed = fp->link_speed;
219+ xcvr = fp->xcvr_type;
220+ lp_advertising = fp->lp_advertising;
221+ } while (read_seqcount_retry(&fp->link_seq, seq));
222+
223+ if (link_up) {
224+ ks->base.speed = speed;
225+ ks->base.duplex = DUPLEX_FULL;
226+ fun_link_modes_to_ethtool(lp_advertising,
227+ ks->link_modes.lp_advertising);
228+ } else {
229+ ks->base.speed = SPEED_UNKNOWN;
230+ ks->base.duplex = DUPLEX_UNKNOWN;
231+ }
232+
233+ ks->base.autoneg = (fp->advertising & FUN_PORT_CAP_AUTONEG) ?
234+ AUTONEG_ENABLE : AUTONEG_DISABLE;
235+ ks->base.port = fun_port_type(xcvr);
236+
237+ fun_link_modes_to_ethtool(fp->port_caps, ks->link_modes.supported);
238+ if (fp->port_caps & (FUN_PORT_CAP_RX_PAUSE | FUN_PORT_CAP_TX_PAUSE))
239+ ethtool_link_ksettings_add_link_mode(ks, supported, Asym_Pause);
240+
241+ fun_link_modes_to_ethtool(fp->advertising, ks->link_modes.advertising);
242+ set_asym_pause(fp->advertising, ks);
243+ return 0;
244+}
245+
246+static u64 fun_advert_modes(const struct ethtool_link_ksettings *ks)
247+{
248+ u64 modes = 0;
249+
250+#define HAS_MODE(mode) \
251+ ethtool_link_ksettings_test_link_mode(ks, advertising, mode)
252+
253+ if (HAS_MODE(1000baseX_Full))
254+ modes |= FUN_PORT_CAP_1000_X;
255+ if (HAS_MODE(10000baseCR_Full) || HAS_MODE(10000baseSR_Full) ||
256+ HAS_MODE(10000baseLR_Full) || HAS_MODE(10000baseER_Full))
257+ modes |= FUN_PORT_CAP_10G_R;
258+ if (HAS_MODE(25000baseCR_Full) || HAS_MODE(25000baseSR_Full))
259+ modes |= FUN_PORT_CAP_25G_R;
260+ if (HAS_MODE(40000baseCR4_Full) || HAS_MODE(40000baseSR4_Full) ||
261+ HAS_MODE(40000baseLR4_Full))
262+ modes |= FUN_PORT_CAP_40G_R4;
263+ if (HAS_MODE(50000baseCR2_Full) || HAS_MODE(50000baseSR2_Full))
264+ modes |= FUN_PORT_CAP_50G_R2;
265+ if (HAS_MODE(50000baseCR_Full) || HAS_MODE(50000baseSR_Full) ||
266+ HAS_MODE(50000baseLR_ER_FR_Full))
267+ modes |= FUN_PORT_CAP_50G_R;
268+ if (HAS_MODE(100000baseCR4_Full) || HAS_MODE(100000baseSR4_Full) ||
269+ HAS_MODE(100000baseLR4_ER4_Full))
270+ modes |= FUN_PORT_CAP_100G_R4;
271+ if (HAS_MODE(100000baseCR2_Full) || HAS_MODE(100000baseSR2_Full) ||
272+ HAS_MODE(100000baseLR2_ER2_FR2_Full))
273+ modes |= FUN_PORT_CAP_100G_R2;
274+
275+ return modes;
276+#undef HAS_MODE
277+}
278+
279+static u64 fun_speed_to_link_mode(unsigned int speed)
280+{
281+ switch (speed) {
282+ case SPEED_100000:
283+ return FUN_PORT_CAP_100G_R4 | FUN_PORT_CAP_100G_R2;
284+ case SPEED_50000:
285+ return FUN_PORT_CAP_50G_R | FUN_PORT_CAP_50G_R2;
286+ case SPEED_40000:
287+ return FUN_PORT_CAP_40G_R4;
288+ case SPEED_25000:
289+ return FUN_PORT_CAP_25G_R;
290+ case SPEED_10000:
291+ return FUN_PORT_CAP_10G_R;
292+ case SPEED_1000:
293+ return FUN_PORT_CAP_1000_X;
294+ default:
295+ return 0;
296+ }
297+}
298+
299+static int fun_change_advert(struct funeth_priv *fp, u64 new_advert)
300+{
301+ int err;
302+
303+ if (new_advert == fp->advertising)
304+ return 0;
305+
306+ err = fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT, new_advert);
307+ if (!err)
308+ fp->advertising = new_advert;
309+ return err;
310+}
311+
312+#define FUN_PORT_CAP_FEC_MASK \
313+ (FUN_PORT_CAP_FEC_NONE | FUN_PORT_CAP_FEC_FC | FUN_PORT_CAP_FEC_RS)
314+
315+static int fun_set_link_ksettings(struct net_device *netdev,
316+ const struct ethtool_link_ksettings *ks)
317+{
318+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {};
319+ struct funeth_priv *fp = netdev_priv(netdev);
320+ u64 new_advert;
321+
322+ /* eswitch ports don't support mode changes */
323+ if (fp->port_caps & FUN_PORT_CAP_VPORT)
324+ return -EOPNOTSUPP;
325+
326+ if (ks->base.duplex == DUPLEX_HALF)
327+ return -EINVAL;
328+ if (ks->base.autoneg == AUTONEG_ENABLE &&
329+ !(fp->port_caps & FUN_PORT_CAP_AUTONEG))
330+ return -EINVAL;
331+
332+ if (ks->base.autoneg == AUTONEG_ENABLE) {
333+ if (linkmode_empty(ks->link_modes.advertising))
334+ return -EINVAL;
335+
336+ fun_link_modes_to_ethtool(fp->port_caps, supported);
337+ if (!linkmode_subset(ks->link_modes.advertising, supported))
338+ return -EINVAL;
339+
340+ new_advert = fun_advert_modes(ks) | FUN_PORT_CAP_AUTONEG;
341+ } else {
342+ new_advert = fun_speed_to_link_mode(ks->base.speed);
343+ new_advert &= fp->port_caps;
344+ if (!new_advert)
345+ return -EINVAL;
346+ }
347+ new_advert |= fp->advertising &
348+ (FUN_PORT_CAP_PAUSE_MASK | FUN_PORT_CAP_FEC_MASK);
349+
350+ return fun_change_advert(fp, new_advert);
351+}
352+
353+static void fun_get_pauseparam(struct net_device *netdev,
354+ struct ethtool_pauseparam *pause)
355+{
356+ const struct funeth_priv *fp = netdev_priv(netdev);
357+ u8 active_pause = fp->active_fc;
358+
359+ pause->rx_pause = !!(active_pause & FUN_PORT_CAP_RX_PAUSE);
360+ pause->tx_pause = !!(active_pause & FUN_PORT_CAP_TX_PAUSE);
361+ pause->autoneg = !!(fp->advertising & FUN_PORT_CAP_AUTONEG);
362+}
363+
364+static int fun_set_pauseparam(struct net_device *netdev,
365+ struct ethtool_pauseparam *pause)
366+{
367+ struct funeth_priv *fp = netdev_priv(netdev);
368+ u64 new_advert;
369+
370+ if (fp->port_caps & FUN_PORT_CAP_VPORT)
371+ return -EOPNOTSUPP;
372+ /* Forcing PAUSE settings with AN enabled is unsupported. */
373+ if (!pause->autoneg && (fp->advertising & FUN_PORT_CAP_AUTONEG))
374+ return -EOPNOTSUPP;
375+ if (pause->autoneg && !(fp->advertising & FUN_PORT_CAP_AUTONEG))
376+ return -EINVAL;
377+ if (pause->tx_pause && !(fp->port_caps & FUN_PORT_CAP_TX_PAUSE))
378+ return -EINVAL;
379+ if (pause->rx_pause && !(fp->port_caps & FUN_PORT_CAP_RX_PAUSE))
380+ return -EINVAL;
381+
382+ new_advert = fp->advertising & ~FUN_PORT_CAP_PAUSE_MASK;
383+ if (pause->tx_pause)
384+ new_advert |= FUN_PORT_CAP_TX_PAUSE;
385+ if (pause->rx_pause)
386+ new_advert |= FUN_PORT_CAP_RX_PAUSE;
387+
388+ return fun_change_advert(fp, new_advert);
389+}
390+
391+static int fun_restart_an(struct net_device *netdev)
392+{
393+ struct funeth_priv *fp = netdev_priv(netdev);
394+
395+ if (!(fp->advertising & FUN_PORT_CAP_AUTONEG))
396+ return -EOPNOTSUPP;
397+
398+ return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT,
399+ FUN_PORT_CAP_AUTONEG);
400+}
401+
402+static int fun_set_phys_id(struct net_device *netdev,
403+ enum ethtool_phys_id_state state)
404+{
405+ struct funeth_priv *fp = netdev_priv(netdev);
406+ unsigned int beacon;
407+
408+ if (fp->port_caps & FUN_PORT_CAP_VPORT)
409+ return -EOPNOTSUPP;
410+ if (state != ETHTOOL_ID_ACTIVE && state != ETHTOOL_ID_INACTIVE)
411+ return -EOPNOTSUPP;
412+
413+ beacon = state == ETHTOOL_ID_ACTIVE ? FUN_PORT_LED_BEACON_ON :
414+ FUN_PORT_LED_BEACON_OFF;
415+ return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_LED, beacon);
416+}
417+
418+static void fun_get_drvinfo(struct net_device *netdev,
419+ struct ethtool_drvinfo *info)
420+{
421+ const struct funeth_priv *fp = netdev_priv(netdev);
422+
423+ strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
424+ strscpy(info->bus_info, pci_name(fp->pdev), sizeof(info->bus_info));
425+}
426+
427+static u32 fun_get_msglevel(struct net_device *netdev)
428+{
429+ const struct funeth_priv *fp = netdev_priv(netdev);
430+
431+ return fp->msg_enable;
432+}
433+
434+static void fun_set_msglevel(struct net_device *netdev, u32 value)
435+{
436+ struct funeth_priv *fp = netdev_priv(netdev);
437+
438+ fp->msg_enable = value;
439+}
440+
441+static int fun_get_regs_len(struct net_device *dev)
442+{
443+ return NVME_REG_ACQ + sizeof(u64);
444+}
445+
446+static void fun_get_regs(struct net_device *dev, struct ethtool_regs *regs,
447+ void *buf)
448+{
449+ const struct funeth_priv *fp = netdev_priv(dev);
450+ void __iomem *bar = fp->fdev->bar;
451+
452+ regs->version = 0;
453+ *(u64 *)(buf + NVME_REG_CAP) = readq(bar + NVME_REG_CAP);
454+ *(u32 *)(buf + NVME_REG_VS) = readl(bar + NVME_REG_VS);
455+ *(u32 *)(buf + NVME_REG_INTMS) = readl(bar + NVME_REG_INTMS);
456+ *(u32 *)(buf + NVME_REG_INTMC) = readl(bar + NVME_REG_INTMC);
457+ *(u32 *)(buf + NVME_REG_CC) = readl(bar + NVME_REG_CC);
458+ *(u32 *)(buf + NVME_REG_CSTS) = readl(bar + NVME_REG_CSTS);
459+ *(u32 *)(buf + NVME_REG_AQA) = readl(bar + NVME_REG_AQA);
460+ *(u64 *)(buf + NVME_REG_ASQ) = readq(bar + NVME_REG_ASQ);
461+ *(u64 *)(buf + NVME_REG_ACQ) = readq(bar + NVME_REG_ACQ);
462+}
463+
464+static int fun_get_coalesce(struct net_device *netdev,
465+ struct ethtool_coalesce *coal,
466+ struct kernel_ethtool_coalesce *kcoal,
467+ struct netlink_ext_ack *ext_ack)
468+{
469+ const struct funeth_priv *fp = netdev_priv(netdev);
470+
471+ coal->rx_coalesce_usecs = fp->rx_coal_usec;
472+ coal->rx_max_coalesced_frames = fp->rx_coal_count;
473+ coal->use_adaptive_rx_coalesce = !fp->cq_irq_db;
474+ coal->tx_coalesce_usecs = fp->tx_coal_usec;
475+ coal->tx_max_coalesced_frames = fp->tx_coal_count;
476+ return 0;
477+}
478+
479+static int fun_set_coalesce(struct net_device *netdev,
480+ struct ethtool_coalesce *coal,
481+ struct kernel_ethtool_coalesce *kcoal,
482+ struct netlink_ext_ack *ext_ack)
483+{
484+ struct funeth_priv *fp = netdev_priv(netdev);
485+ struct funeth_rxq **rxqs;
486+ unsigned int i, db_val;
487+
488+ if (coal->rx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M ||
489+ coal->rx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M ||
490+ (coal->rx_coalesce_usecs | coal->rx_max_coalesced_frames) == 0 ||
491+ coal->tx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M ||
492+ coal->tx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M ||
493+ (coal->tx_coalesce_usecs | coal->tx_max_coalesced_frames) == 0)
494+ return -EINVAL;
495+
496+ /* a timer is required if there's any coalescing */
497+ if ((coal->rx_max_coalesced_frames > 1 && !coal->rx_coalesce_usecs) ||
498+ (coal->tx_max_coalesced_frames > 1 && !coal->tx_coalesce_usecs))
499+ return -EINVAL;
500+
501+ fp->rx_coal_usec = coal->rx_coalesce_usecs;
502+ fp->rx_coal_count = coal->rx_max_coalesced_frames;
503+ fp->tx_coal_usec = coal->tx_coalesce_usecs;
504+ fp->tx_coal_count = coal->tx_max_coalesced_frames;
505+
506+ db_val = FUN_IRQ_CQ_DB(fp->rx_coal_usec, fp->rx_coal_count);
507+ WRITE_ONCE(fp->cq_irq_db, db_val);
508+
509+ rxqs = rtnl_dereference(fp->rxqs);
510+ if (!rxqs)
511+ return 0;
512+
513+ for (i = 0; i < netdev->real_num_rx_queues; i++)
514+ WRITE_ONCE(rxqs[i]->irq_db_val, db_val);
515+
516+ db_val = FUN_IRQ_SQ_DB(fp->tx_coal_usec, fp->tx_coal_count);
517+ for (i = 0; i < netdev->real_num_tx_queues; i++)
518+ WRITE_ONCE(fp->txqs[i]->irq_db_val, db_val);
519+
520+ return 0;
521+}
522+
523+static void fun_get_channels(struct net_device *netdev,
524+ struct ethtool_channels *chan)
525+{
526+ chan->max_rx = netdev->num_rx_queues;
527+ chan->rx_count = netdev->real_num_rx_queues;
528+
529+ chan->max_tx = netdev->num_tx_queues;
530+ chan->tx_count = netdev->real_num_tx_queues;
531+}
532+
533+static int fun_set_channels(struct net_device *netdev,
534+ struct ethtool_channels *chan)
535+{
536+ if (!chan->tx_count || !chan->rx_count)
537+ return -EINVAL;
538+
539+ if (chan->tx_count == netdev->real_num_tx_queues &&
540+ chan->rx_count == netdev->real_num_rx_queues)
541+ return 0;
542+
543+ if (netif_running(netdev))
544+ return fun_change_num_queues(netdev, chan->tx_count,
545+ chan->rx_count);
546+
547+ fun_set_ring_count(netdev, chan->tx_count, chan->rx_count);
548+ return 0;
549+}
550+
551+static void fun_get_ringparam(struct net_device *netdev,
552+ struct ethtool_ringparam *ring,
553+ struct kernel_ethtool_ringparam *kring,
554+ struct netlink_ext_ack *extack)
555+{
556+ const struct funeth_priv *fp = netdev_priv(netdev);
557+ unsigned int max_depth = fp->fdev->q_depth;
558+
559+ /* We size CQs to be twice the RQ depth so max RQ depth is half the
560+ * max queue depth.
561+ */
562+ ring->rx_max_pending = max_depth / 2;
563+ ring->tx_max_pending = max_depth;
564+
565+ ring->rx_pending = fp->rq_depth;
566+ ring->tx_pending = fp->sq_depth;
567+
568+ kring->rx_buf_len = PAGE_SIZE;
569+ kring->cqe_size = FUNETH_CQE_SIZE;
570+}
571+
572+static int fun_set_ringparam(struct net_device *netdev,
573+ struct ethtool_ringparam *ring,
574+ struct kernel_ethtool_ringparam *kring,
575+ struct netlink_ext_ack *extack)
576+{
577+ struct funeth_priv *fp = netdev_priv(netdev);
578+ int rc;
579+
580+ if (ring->rx_mini_pending || ring->rx_jumbo_pending)
581+ return -EINVAL;
582+
583+ /* queue depths must be powers-of-2 */
584+ if (!is_power_of_2(ring->rx_pending) ||
585+ !is_power_of_2(ring->tx_pending))
586+ return -EINVAL;
587+
588+ if (ring->rx_pending < FUNETH_MIN_QDEPTH ||
589+ ring->tx_pending < FUNETH_MIN_QDEPTH)
590+ return -EINVAL;
591+
592+ if (fp->sq_depth == ring->tx_pending &&
593+ fp->rq_depth == ring->rx_pending)
594+ return 0;
595+
596+ if (netif_running(netdev)) {
597+ struct fun_qset req = {
598+ .cq_depth = 2 * ring->rx_pending,
599+ .rq_depth = ring->rx_pending,
600+ .sq_depth = ring->tx_pending
601+ };
602+
603+ rc = fun_replace_queues(netdev, &req, extack);
604+ if (rc)
605+ return rc;
606+ }
607+
608+ fp->sq_depth = ring->tx_pending;
609+ fp->rq_depth = ring->rx_pending;
610+ fp->cq_depth = 2 * fp->rq_depth;
611+ return 0;
612+}
613+
614+static int fun_get_sset_count(struct net_device *dev, int sset)
615+{
616+ const struct funeth_priv *fp = netdev_priv(dev);
617+ int n;
618+
619+ switch (sset) {
620+ case ETH_SS_STATS:
621+ n = (dev->real_num_tx_queues + 1) * ARRAY_SIZE(txq_stat_names) +
622+ (dev->real_num_rx_queues + 1) * ARRAY_SIZE(rxq_stat_names) +
623+ (fp->num_xdpqs + 1) * ARRAY_SIZE(xdpq_stat_names) +
624+ ARRAY_SIZE(tls_stat_names);
625+ if (fp->port_caps & FUN_PORT_CAP_STATS) {
626+ n += ARRAY_SIZE(mac_tx_stat_names) +
627+ ARRAY_SIZE(mac_rx_stat_names);
628+ }
629+ return n;
630+ default:
631+ break;
632+ }
633+ return 0;
634+}
635+
636+static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data)
637+{
638+ const struct funeth_priv *fp = netdev_priv(netdev);
639+ unsigned int i, j;
640+ u8 *p = data;
641+
642+ switch (sset) {
643+ case ETH_SS_STATS:
644+ if (fp->port_caps & FUN_PORT_CAP_STATS) {
645+ memcpy(p, mac_tx_stat_names, sizeof(mac_tx_stat_names));
646+ p += sizeof(mac_tx_stat_names);
647+ memcpy(p, mac_rx_stat_names, sizeof(mac_rx_stat_names));
648+ p += sizeof(mac_rx_stat_names);
649+ }
650+
651+ for (i = 0; i < netdev->real_num_tx_queues; i++) {
652+ for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)
653+ ethtool_sprintf(&p, "%s[%u]", txq_stat_names[j],
654+ i);
655+ }
656+ for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)
657+ ethtool_sprintf(&p, txq_stat_names[j]);
658+
659+ for (i = 0; i < fp->num_xdpqs; i++) {
660+ for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)
661+ ethtool_sprintf(&p, "%s[%u]",
662+ xdpq_stat_names[j], i);
663+ }
664+ for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)
665+ ethtool_sprintf(&p, xdpq_stat_names[j]);
666+
667+ for (i = 0; i < netdev->real_num_rx_queues; i++) {
668+ for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)
669+ ethtool_sprintf(&p, "%s[%u]", rxq_stat_names[j],
670+ i);
671+ }
672+ for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)
673+ ethtool_sprintf(&p, rxq_stat_names[j]);
674+
675+ for (j = 0; j < ARRAY_SIZE(tls_stat_names); j++)
676+ ethtool_sprintf(&p, tls_stat_names[j]);
677+ break;
678+ default:
679+ break;
680+ }
681+}
682+
683+static u64 *get_mac_stats(const struct funeth_priv *fp, u64 *data)
684+{
685+#define TX_STAT(s) \
686+ *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s])
687+
688+ TX_STAT(etherStatsOctets);
689+ TX_STAT(etherStatsPkts);
690+ TX_STAT(VLANTransmittedOK);
691+ TX_STAT(ifOutUcastPkts);
692+ TX_STAT(ifOutMulticastPkts);
693+ TX_STAT(ifOutBroadcastPkts);
694+ TX_STAT(ifOutErrors);
695+ TX_STAT(CBFCPAUSEFramesTransmitted_0);
696+ TX_STAT(CBFCPAUSEFramesTransmitted_1);
697+ TX_STAT(CBFCPAUSEFramesTransmitted_2);
698+ TX_STAT(CBFCPAUSEFramesTransmitted_3);
699+ TX_STAT(CBFCPAUSEFramesTransmitted_4);
700+ TX_STAT(CBFCPAUSEFramesTransmitted_5);
701+ TX_STAT(CBFCPAUSEFramesTransmitted_6);
702+ TX_STAT(CBFCPAUSEFramesTransmitted_7);
703+ TX_STAT(CBFCPAUSEFramesTransmitted_8);
704+ TX_STAT(CBFCPAUSEFramesTransmitted_9);
705+ TX_STAT(CBFCPAUSEFramesTransmitted_10);
706+ TX_STAT(CBFCPAUSEFramesTransmitted_11);
707+ TX_STAT(CBFCPAUSEFramesTransmitted_12);
708+ TX_STAT(CBFCPAUSEFramesTransmitted_13);
709+ TX_STAT(CBFCPAUSEFramesTransmitted_14);
710+ TX_STAT(CBFCPAUSEFramesTransmitted_15);
711+
712+#define RX_STAT(s) *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_##s])
713+
714+ RX_STAT(etherStatsOctets);
715+ RX_STAT(etherStatsPkts);
716+ RX_STAT(VLANReceivedOK);
717+ RX_STAT(ifInUcastPkts);
718+ RX_STAT(ifInMulticastPkts);
719+ RX_STAT(ifInBroadcastPkts);
720+ RX_STAT(etherStatsDropEvents);
721+ RX_STAT(ifInErrors);
722+ RX_STAT(aAlignmentErrors);
723+ RX_STAT(CBFCPAUSEFramesReceived_0);
724+ RX_STAT(CBFCPAUSEFramesReceived_1);
725+ RX_STAT(CBFCPAUSEFramesReceived_2);
726+ RX_STAT(CBFCPAUSEFramesReceived_3);
727+ RX_STAT(CBFCPAUSEFramesReceived_4);
728+ RX_STAT(CBFCPAUSEFramesReceived_5);
729+ RX_STAT(CBFCPAUSEFramesReceived_6);
730+ RX_STAT(CBFCPAUSEFramesReceived_7);
731+ RX_STAT(CBFCPAUSEFramesReceived_8);
732+ RX_STAT(CBFCPAUSEFramesReceived_9);
733+ RX_STAT(CBFCPAUSEFramesReceived_10);
734+ RX_STAT(CBFCPAUSEFramesReceived_11);
735+ RX_STAT(CBFCPAUSEFramesReceived_12);
736+ RX_STAT(CBFCPAUSEFramesReceived_13);
737+ RX_STAT(CBFCPAUSEFramesReceived_14);
738+ RX_STAT(CBFCPAUSEFramesReceived_15);
739+
740+ return data;
741+
742+#undef TX_STAT
743+#undef RX_STAT
744+}
745+
746+static void fun_get_ethtool_stats(struct net_device *netdev,
747+ struct ethtool_stats *stats, u64 *data)
748+{
749+ const struct funeth_priv *fp = netdev_priv(netdev);
750+ struct funeth_txq_stats txs;
751+ struct funeth_rxq_stats rxs;
752+ struct funeth_txq **xdpqs;
753+ struct funeth_rxq **rxqs;
754+ unsigned int i, start;
755+ u64 *totals, *tot;
756+
757+ if (fp->port_caps & FUN_PORT_CAP_STATS)
758+ data = get_mac_stats(fp, data);
759+
760+ rxqs = rtnl_dereference(fp->rxqs);
761+ if (!rxqs)
762+ return;
763+
764+#define ADD_STAT(cnt) do { \
765+ *data = (cnt); *tot++ += *data++; \
766+} while (0)
767+
768+ /* Tx queues */
769+ totals = data + netdev->real_num_tx_queues * ARRAY_SIZE(txq_stat_names);
770+
771+ for (i = 0; i < netdev->real_num_tx_queues; i++) {
772+ tot = totals;
773+
774+ FUN_QSTAT_READ(fp->txqs[i], start, txs);
775+
776+ ADD_STAT(txs.tx_pkts);
777+ ADD_STAT(txs.tx_bytes);
778+ ADD_STAT(txs.tx_cso);
779+ ADD_STAT(txs.tx_tso);
780+ ADD_STAT(txs.tx_encap_tso);
781+ ADD_STAT(txs.tx_more);
782+ ADD_STAT(txs.tx_nstops);
783+ ADD_STAT(txs.tx_nrestarts);
784+ ADD_STAT(txs.tx_map_err);
785+ ADD_STAT(txs.tx_tls_pkts);
786+ ADD_STAT(txs.tx_tls_bytes);
787+ ADD_STAT(txs.tx_tls_fallback);
788+ ADD_STAT(txs.tx_tls_drops);
789+ }
790+ data += ARRAY_SIZE(txq_stat_names);
791+
792+ /* XDP Tx queues */
793+ xdpqs = rtnl_dereference(fp->xdpqs);
794+ totals = data + fp->num_xdpqs * ARRAY_SIZE(xdpq_stat_names);
795+
796+ for (i = 0; i < fp->num_xdpqs; i++) {
797+ tot = totals;
798+
799+ FUN_QSTAT_READ(xdpqs[i], start, txs);
800+
801+ ADD_STAT(txs.tx_pkts);
802+ ADD_STAT(txs.tx_bytes);
803+ ADD_STAT(txs.tx_xdp_full);
804+ ADD_STAT(txs.tx_map_err);
805+ }
806+ data += ARRAY_SIZE(xdpq_stat_names);
807+
808+ /* Rx queues */
809+ totals = data + netdev->real_num_rx_queues * ARRAY_SIZE(rxq_stat_names);
810+
811+ for (i = 0; i < netdev->real_num_rx_queues; i++) {
812+ tot = totals;
813+
814+ FUN_QSTAT_READ(rxqs[i], start, rxs);
815+
816+ ADD_STAT(rxs.rx_pkts);
817+ ADD_STAT(rxs.rx_bytes);
818+ ADD_STAT(rxs.rx_cso);
819+ ADD_STAT(rxs.gro_pkts);
820+ ADD_STAT(rxs.gro_merged);
821+ ADD_STAT(rxs.xdp_tx);
822+ ADD_STAT(rxs.xdp_redir);
823+ ADD_STAT(rxs.xdp_drops);
824+ ADD_STAT(rxs.rx_bufs);
825+ ADD_STAT(rxs.rx_page_alloc);
826+ ADD_STAT(rxs.rx_mem_drops + rxs.xdp_err);
827+ ADD_STAT(rxs.rx_budget);
828+ ADD_STAT(rxs.rx_map_err);
829+ }
830+ data += ARRAY_SIZE(rxq_stat_names);
831+#undef ADD_STAT
832+
833+ *data++ = atomic64_read(&fp->tx_tls_add);
834+ *data++ = atomic64_read(&fp->tx_tls_del);
835+ *data++ = atomic64_read(&fp->tx_tls_resync);
836+}
837+
838+#define RX_STAT(fp, s) be64_to_cpu((fp)->stats[PORT_MAC_RX_##s])
839+#define TX_STAT(fp, s) \
840+ be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s])
841+#define FEC_STAT(fp, s) \
842+ be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + \
843+ PORT_MAC_TX_STATS_MAX + PORT_MAC_FEC_##s])
844+
845+static void fun_get_pause_stats(struct net_device *netdev,
846+ struct ethtool_pause_stats *stats)
847+{
848+ const struct funeth_priv *fp = netdev_priv(netdev);
849+
850+ if (!(fp->port_caps & FUN_PORT_CAP_STATS))
851+ return;
852+
853+ stats->tx_pause_frames = TX_STAT(fp, aPAUSEMACCtrlFramesTransmitted);
854+ stats->rx_pause_frames = RX_STAT(fp, aPAUSEMACCtrlFramesReceived);
855+}
856+
857+static void fun_get_802_3_stats(struct net_device *netdev,
858+ struct ethtool_eth_mac_stats *stats)
859+{
860+ const struct funeth_priv *fp = netdev_priv(netdev);
861+
862+ if (!(fp->port_caps & FUN_PORT_CAP_STATS))
863+ return;
864+
865+ stats->FramesTransmittedOK = TX_STAT(fp, aFramesTransmittedOK);
866+ stats->FramesReceivedOK = RX_STAT(fp, aFramesReceivedOK);
867+ stats->FrameCheckSequenceErrors = RX_STAT(fp, aFrameCheckSequenceErrors);
868+ stats->OctetsTransmittedOK = TX_STAT(fp, OctetsTransmittedOK);
869+ stats->OctetsReceivedOK = RX_STAT(fp, OctetsReceivedOK);
870+ stats->InRangeLengthErrors = RX_STAT(fp, aInRangeLengthErrors);
871+ stats->FrameTooLongErrors = RX_STAT(fp, aFrameTooLongErrors);
872+}
873+
874+static void fun_get_802_3_ctrl_stats(struct net_device *netdev,
875+ struct ethtool_eth_ctrl_stats *stats)
876+{
877+ const struct funeth_priv *fp = netdev_priv(netdev);
878+
879+ if (!(fp->port_caps & FUN_PORT_CAP_STATS))
880+ return;
881+
882+ stats->MACControlFramesTransmitted = TX_STAT(fp, MACControlFramesTransmitted);
883+ stats->MACControlFramesReceived = RX_STAT(fp, MACControlFramesReceived);
884+}
885+
886+static void fun_get_rmon_stats(struct net_device *netdev,
887+ struct ethtool_rmon_stats *stats,
888+ const struct ethtool_rmon_hist_range **ranges)
889+{
890+ static const struct ethtool_rmon_hist_range rmon_ranges[] = {
891+ { 64, 64 },
892+ { 65, 127 },
893+ { 128, 255 },
894+ { 256, 511 },
895+ { 512, 1023 },
896+ { 1024, 1518 },
897+ { 1519, 32767 },
898+ {}
899+ };
900+
901+ const struct funeth_priv *fp = netdev_priv(netdev);
902+
903+ if (!(fp->port_caps & FUN_PORT_CAP_STATS))
904+ return;
905+
906+ stats->undersize_pkts = RX_STAT(fp, etherStatsUndersizePkts);
907+ stats->oversize_pkts = RX_STAT(fp, etherStatsOversizePkts);
908+ stats->fragments = RX_STAT(fp, etherStatsFragments);
909+ stats->jabbers = RX_STAT(fp, etherStatsJabbers);
910+
911+ stats->hist[0] = RX_STAT(fp, etherStatsPkts64Octets);
912+ stats->hist[1] = RX_STAT(fp, etherStatsPkts65to127Octets);
913+ stats->hist[2] = RX_STAT(fp, etherStatsPkts128to255Octets);
914+ stats->hist[3] = RX_STAT(fp, etherStatsPkts256to511Octets);
915+ stats->hist[4] = RX_STAT(fp, etherStatsPkts512to1023Octets);
916+ stats->hist[5] = RX_STAT(fp, etherStatsPkts1024to1518Octets);
917+ stats->hist[6] = RX_STAT(fp, etherStatsPkts1519toMaxOctets);
918+
919+ stats->hist_tx[0] = TX_STAT(fp, etherStatsPkts64Octets);
920+ stats->hist_tx[1] = TX_STAT(fp, etherStatsPkts65to127Octets);
921+ stats->hist_tx[2] = TX_STAT(fp, etherStatsPkts128to255Octets);
922+ stats->hist_tx[3] = TX_STAT(fp, etherStatsPkts256to511Octets);
923+ stats->hist_tx[4] = TX_STAT(fp, etherStatsPkts512to1023Octets);
924+ stats->hist_tx[5] = TX_STAT(fp, etherStatsPkts1024to1518Octets);
925+ stats->hist_tx[6] = TX_STAT(fp, etherStatsPkts1519toMaxOctets);
926+
927+ *ranges = rmon_ranges;
928+}
929+
930+static void fun_get_fec_stats(struct net_device *netdev,
931+ struct ethtool_fec_stats *stats)
932+{
933+ const struct funeth_priv *fp = netdev_priv(netdev);
934+
935+ if (!(fp->port_caps & FUN_PORT_CAP_STATS))
936+ return;
937+
938+ stats->corrected_blocks.total = FEC_STAT(fp, Correctable);
939+ stats->uncorrectable_blocks.total = FEC_STAT(fp, Uncorrectable);
940+}
941+
942+#undef RX_STAT
943+#undef TX_STAT
944+#undef FEC_STAT
945+
946+static int fun_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
947+ u32 *rule_locs)
948+{
949+ switch (cmd->cmd) {
950+ case ETHTOOL_GRXRINGS:
951+ cmd->data = netdev->real_num_rx_queues;
952+ return 0;
953+ default:
954+ break;
955+ }
956+ return -EOPNOTSUPP;
957+}
958+
959+static int fun_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info)
960+{
961+ return 0;
962+}
963+
964+static u32 fun_get_rxfh_indir_size(struct net_device *netdev)
965+{
966+ const struct funeth_priv *fp = netdev_priv(netdev);
967+
968+ return fp->indir_table_nentries;
969+}
970+
971+static u32 fun_get_rxfh_key_size(struct net_device *netdev)
972+{
973+ const struct funeth_priv *fp = netdev_priv(netdev);
974+
975+ return sizeof(fp->rss_key);
976+}
977+
978+static int fun_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
979+ u8 *hfunc)
980+{
981+ const struct funeth_priv *fp = netdev_priv(netdev);
982+
983+ if (!fp->rss_cfg)
984+ return -EOPNOTSUPP;
985+
986+ if (indir)
987+ memcpy(indir, fp->indir_table,
988+ sizeof(u32) * fp->indir_table_nentries);
989+
990+ if (key)
991+ memcpy(key, fp->rss_key, sizeof(fp->rss_key));
992+
993+ if (hfunc)
994+ *hfunc = fp->hash_algo == FUN_ETH_RSS_ALG_TOEPLITZ ?
995+ ETH_RSS_HASH_TOP : ETH_RSS_HASH_CRC32;
996+
997+ return 0;
998+}
999+
1000+static int fun_set_rxfh(struct net_device *netdev, const u32 *indir,
1001+ const u8 *key, const u8 hfunc)
1002+{
1003+ struct funeth_priv *fp = netdev_priv(netdev);
1004+ const u32 *rss_indir = indir ? indir : fp->indir_table;
1005+ const u8 *rss_key = key ? key : fp->rss_key;
1006+ enum fun_eth_hash_alg algo;
1007+
1008+ if (!fp->rss_cfg)
1009+ return -EOPNOTSUPP;
1010+
1011+ if (hfunc == ETH_RSS_HASH_NO_CHANGE)
1012+ algo = fp->hash_algo;
1013+ else if (hfunc == ETH_RSS_HASH_CRC32)
1014+ algo = FUN_ETH_RSS_ALG_CRC32;
1015+ else if (hfunc == ETH_RSS_HASH_TOP)
1016+ algo = FUN_ETH_RSS_ALG_TOEPLITZ;
1017+ else
1018+ return -EINVAL;
1019+
1020+ /* If the port is enabled try to reconfigure RSS and keep the new
1021+ * settings if successful. If it is down we update the RSS settings
1022+ * and apply them at the next UP time.
1023+ */
1024+ if (netif_running(netdev)) {
1025+ int rc = fun_config_rss(netdev, algo, rss_key, rss_indir,
1026+ FUN_ADMIN_SUBOP_MODIFY);
1027+ if (rc)
1028+ return rc;
1029+ }
1030+
1031+ fp->hash_algo = algo;
1032+ if (key)
1033+ memcpy(fp->rss_key, key, sizeof(fp->rss_key));
1034+ if (indir)
1035+ memcpy(fp->indir_table, indir,
1036+ sizeof(u32) * fp->indir_table_nentries);
1037+ return 0;
1038+}
1039+
1040+static int fun_get_ts_info(struct net_device *netdev,
1041+ struct ethtool_ts_info *info)
1042+{
1043+ info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
1044+ SOF_TIMESTAMPING_RX_HARDWARE |
1045+ SOF_TIMESTAMPING_TX_SOFTWARE |
1046+ SOF_TIMESTAMPING_SOFTWARE |
1047+ SOF_TIMESTAMPING_RAW_HARDWARE;
1048+ info->phc_index = -1;
1049+ info->tx_types = BIT(HWTSTAMP_TX_OFF);
1050+ info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
1051+ return 0;
1052+}
1053+
1054+static unsigned int to_ethtool_fec(unsigned int fun_fec)
1055+{
1056+ unsigned int fec = 0;
1057+
1058+ if (fun_fec == FUN_PORT_FEC_NA)
1059+ fec |= ETHTOOL_FEC_NONE;
1060+ if (fun_fec & FUN_PORT_FEC_OFF)
1061+ fec |= ETHTOOL_FEC_OFF;
1062+ if (fun_fec & FUN_PORT_FEC_RS)
1063+ fec |= ETHTOOL_FEC_RS;
1064+ if (fun_fec & FUN_PORT_FEC_FC)
1065+ fec |= ETHTOOL_FEC_BASER;
1066+ if (fun_fec & FUN_PORT_FEC_AUTO)
1067+ fec |= ETHTOOL_FEC_AUTO;
1068+ return fec;
1069+}
1070+
1071+static int fun_get_fecparam(struct net_device *netdev,
1072+ struct ethtool_fecparam *fec)
1073+{
1074+ struct funeth_priv *fp = netdev_priv(netdev);
1075+ u64 fec_data;
1076+ int rc;
1077+
1078+ rc = fun_port_read_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, &fec_data);
1079+ if (rc)
1080+ return rc;
1081+
1082+ fec->active_fec = to_ethtool_fec(fec_data & 0xff);
1083+ fec->fec = to_ethtool_fec(fec_data >> 8);
1084+ return 0;
1085+}
1086+
1087+static int fun_set_fecparam(struct net_device *netdev,
1088+ struct ethtool_fecparam *fec)
1089+{
1090+ struct funeth_priv *fp = netdev_priv(netdev);
1091+ u64 fec_mode;
1092+
1093+ switch (fec->fec) {
1094+ case ETHTOOL_FEC_AUTO:
1095+ fec_mode = FUN_PORT_FEC_AUTO;
1096+ break;
1097+ case ETHTOOL_FEC_OFF:
1098+ if (!(fp->port_caps & FUN_PORT_CAP_FEC_NONE))
1099+ return -EINVAL;
1100+ fec_mode = FUN_PORT_FEC_OFF;
1101+ break;
1102+ case ETHTOOL_FEC_BASER:
1103+ if (!(fp->port_caps & FUN_PORT_CAP_FEC_FC))
1104+ return -EINVAL;
1105+ fec_mode = FUN_PORT_FEC_FC;
1106+ break;
1107+ case ETHTOOL_FEC_RS:
1108+ if (!(fp->port_caps & FUN_PORT_CAP_FEC_RS))
1109+ return -EINVAL;
1110+ fec_mode = FUN_PORT_FEC_RS;
1111+ break;
1112+ default:
1113+ return -EINVAL;
1114+ }
1115+
1116+ return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, fec_mode);
1117+}
1118+
1119+static const struct ethtool_ops fun_ethtool_ops = {
1120+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
1121+ ETHTOOL_COALESCE_MAX_FRAMES,
1122+ .get_link_ksettings = fun_get_link_ksettings,
1123+ .set_link_ksettings = fun_set_link_ksettings,
1124+ .set_phys_id = fun_set_phys_id,
1125+ .get_drvinfo = fun_get_drvinfo,
1126+ .get_msglevel = fun_get_msglevel,
1127+ .set_msglevel = fun_set_msglevel,
1128+ .get_regs_len = fun_get_regs_len,
1129+ .get_regs = fun_get_regs,
1130+ .get_link = ethtool_op_get_link,
1131+ .get_coalesce = fun_get_coalesce,
1132+ .set_coalesce = fun_set_coalesce,
1133+ .get_ts_info = fun_get_ts_info,
1134+ .get_ringparam = fun_get_ringparam,
1135+ .set_ringparam = fun_set_ringparam,
1136+ .get_sset_count = fun_get_sset_count,
1137+ .get_strings = fun_get_strings,
1138+ .get_ethtool_stats = fun_get_ethtool_stats,
1139+ .get_rxnfc = fun_get_rxnfc,
1140+ .set_rxnfc = fun_set_rxnfc,
1141+ .get_rxfh_indir_size = fun_get_rxfh_indir_size,
1142+ .get_rxfh_key_size = fun_get_rxfh_key_size,
1143+ .get_rxfh = fun_get_rxfh,
1144+ .set_rxfh = fun_set_rxfh,
1145+ .get_channels = fun_get_channels,
1146+ .set_channels = fun_set_channels,
1147+ .get_fecparam = fun_get_fecparam,
1148+ .set_fecparam = fun_set_fecparam,
1149+ .get_pauseparam = fun_get_pauseparam,
1150+ .set_pauseparam = fun_set_pauseparam,
1151+ .nway_reset = fun_restart_an,
1152+ .get_pause_stats = fun_get_pause_stats,
1153+ .get_fec_stats = fun_get_fec_stats,
1154+ .get_eth_mac_stats = fun_get_802_3_stats,
1155+ .get_eth_ctrl_stats = fun_get_802_3_ctrl_stats,
1156+ .get_rmon_stats = fun_get_rmon_stats,
1157+};
1158+
1159+void fun_set_ethtool_ops(struct net_device *netdev)
1160+{
1161+ netdev->ethtool_ops = &fun_ethtool_ops;
1162+}