xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
196de2506SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
296de2506SJakub Kicinski /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
34c352362SJakub Kicinski 
44c352362SJakub Kicinski /*
54c352362SJakub Kicinski  * nfp_net_ethtool.c
64c352362SJakub Kicinski  * Netronome network device driver: ethtool support
74c352362SJakub Kicinski  * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
84c352362SJakub Kicinski  *          Jason McMullan <jason.mcmullan@netronome.com>
94c352362SJakub Kicinski  *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
104c352362SJakub Kicinski  *          Brad Petrus <brad.petrus@netronome.com>
114c352362SJakub Kicinski  */
124c352362SJakub Kicinski 
139ff304bfSJakub Kicinski #include <linux/bitfield.h>
144c352362SJakub Kicinski #include <linux/kernel.h>
154c352362SJakub Kicinski #include <linux/netdevice.h>
164c352362SJakub Kicinski #include <linux/etherdevice.h>
174c352362SJakub Kicinski #include <linux/interrupt.h>
184c352362SJakub Kicinski #include <linux/pci.h>
194c352362SJakub Kicinski #include <linux/ethtool.h>
207a741565SDirk van der Merwe #include <linux/firmware.h>
2161f7c6f4SDirk van der Merwe #include <linux/sfp.h>
224c352362SJakub Kicinski 
23bd5ca062SJakub Kicinski #include "nfpcore/nfp.h"
247f3aa620SJakub Kicinski #include "nfpcore/nfp_dev.h"
25ce22f5a2SJakub Kicinski #include "nfpcore/nfp_nsp.h"
267ac9ebd5SJakub Kicinski #include "nfp_app.h"
27d79e19f5SCarl Heymann #include "nfp_main.h"
284c352362SJakub Kicinski #include "nfp_net_ctrl.h"
29d6488c49SJakub Kicinski #include "nfp_net_dp.h"
304c352362SJakub Kicinski #include "nfp_net.h"
31eb488c26SJakub Kicinski #include "nfp_port.h"
3215137daeSFei Qin #include "nfpcore/nfp_cpp.h"
334c352362SJakub Kicinski 
341cfcc97bSJakub Kicinski struct nfp_et_stat {
354c352362SJakub Kicinski 	char name[ETH_GSTRING_LEN];
364c352362SJakub Kicinski 	int off;
374c352362SJakub Kicinski };
384c352362SJakub Kicinski 
391cfcc97bSJakub Kicinski static const struct nfp_et_stat nfp_net_et_stats[] = {
404c352362SJakub Kicinski 	/* Stats from the device */
411cfcc97bSJakub Kicinski 	{ "dev_rx_discards",	NFP_NET_CFG_STATS_RX_DISCARDS },
421cfcc97bSJakub Kicinski 	{ "dev_rx_errors",	NFP_NET_CFG_STATS_RX_ERRORS },
431cfcc97bSJakub Kicinski 	{ "dev_rx_bytes",	NFP_NET_CFG_STATS_RX_OCTETS },
441cfcc97bSJakub Kicinski 	{ "dev_rx_uc_bytes",	NFP_NET_CFG_STATS_RX_UC_OCTETS },
451cfcc97bSJakub Kicinski 	{ "dev_rx_mc_bytes",	NFP_NET_CFG_STATS_RX_MC_OCTETS },
461cfcc97bSJakub Kicinski 	{ "dev_rx_bc_bytes",	NFP_NET_CFG_STATS_RX_BC_OCTETS },
471cfcc97bSJakub Kicinski 	{ "dev_rx_pkts",	NFP_NET_CFG_STATS_RX_FRAMES },
481cfcc97bSJakub Kicinski 	{ "dev_rx_mc_pkts",	NFP_NET_CFG_STATS_RX_MC_FRAMES },
491cfcc97bSJakub Kicinski 	{ "dev_rx_bc_pkts",	NFP_NET_CFG_STATS_RX_BC_FRAMES },
504c352362SJakub Kicinski 
511cfcc97bSJakub Kicinski 	{ "dev_tx_discards",	NFP_NET_CFG_STATS_TX_DISCARDS },
521cfcc97bSJakub Kicinski 	{ "dev_tx_errors",	NFP_NET_CFG_STATS_TX_ERRORS },
531cfcc97bSJakub Kicinski 	{ "dev_tx_bytes",	NFP_NET_CFG_STATS_TX_OCTETS },
541cfcc97bSJakub Kicinski 	{ "dev_tx_uc_bytes",	NFP_NET_CFG_STATS_TX_UC_OCTETS },
551cfcc97bSJakub Kicinski 	{ "dev_tx_mc_bytes",	NFP_NET_CFG_STATS_TX_MC_OCTETS },
561cfcc97bSJakub Kicinski 	{ "dev_tx_bc_bytes",	NFP_NET_CFG_STATS_TX_BC_OCTETS },
571cfcc97bSJakub Kicinski 	{ "dev_tx_pkts",	NFP_NET_CFG_STATS_TX_FRAMES },
581cfcc97bSJakub Kicinski 	{ "dev_tx_mc_pkts",	NFP_NET_CFG_STATS_TX_MC_FRAMES },
591cfcc97bSJakub Kicinski 	{ "dev_tx_bc_pkts",	NFP_NET_CFG_STATS_TX_BC_FRAMES },
6066860bebSJakub Kicinski 
611cfcc97bSJakub Kicinski 	{ "bpf_pass_pkts",	NFP_NET_CFG_STATS_APP0_FRAMES },
621cfcc97bSJakub Kicinski 	{ "bpf_pass_bytes",	NFP_NET_CFG_STATS_APP0_BYTES },
6366860bebSJakub Kicinski 	/* see comments in outro functions in nfp_bpf_jit.c to find out
6466860bebSJakub Kicinski 	 * how different BPF modes use app-specific counters
6566860bebSJakub Kicinski 	 */
661cfcc97bSJakub Kicinski 	{ "bpf_app1_pkts",	NFP_NET_CFG_STATS_APP1_FRAMES },
671cfcc97bSJakub Kicinski 	{ "bpf_app1_bytes",	NFP_NET_CFG_STATS_APP1_BYTES },
681cfcc97bSJakub Kicinski 	{ "bpf_app2_pkts",	NFP_NET_CFG_STATS_APP2_FRAMES },
691cfcc97bSJakub Kicinski 	{ "bpf_app2_bytes",	NFP_NET_CFG_STATS_APP2_BYTES },
701cfcc97bSJakub Kicinski 	{ "bpf_app3_pkts",	NFP_NET_CFG_STATS_APP3_FRAMES },
711cfcc97bSJakub Kicinski 	{ "bpf_app3_bytes",	NFP_NET_CFG_STATS_APP3_BYTES },
724c352362SJakub Kicinski };
734c352362SJakub Kicinski 
74098ce840SJakub Kicinski static const struct nfp_et_stat nfp_mac_et_stats[] = {
75098ce840SJakub Kicinski 	{ "rx_octets",			NFP_MAC_STATS_RX_IN_OCTETS, },
76098ce840SJakub Kicinski 	{ "rx_frame_too_long_errors",
77098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_FRAME_TOO_LONG_ERRORS, },
78098ce840SJakub Kicinski 	{ "rx_range_length_errors",	NFP_MAC_STATS_RX_RANGE_LENGTH_ERRORS, },
79745eaf9aSPieter Jansen van Vuuren 	{ "rx_vlan_received_ok",	NFP_MAC_STATS_RX_VLAN_RECEIVED_OK, },
80098ce840SJakub Kicinski 	{ "rx_errors",			NFP_MAC_STATS_RX_IN_ERRORS, },
81098ce840SJakub Kicinski 	{ "rx_broadcast_pkts",		NFP_MAC_STATS_RX_IN_BROADCAST_PKTS, },
82098ce840SJakub Kicinski 	{ "rx_drop_events",		NFP_MAC_STATS_RX_DROP_EVENTS, },
83098ce840SJakub Kicinski 	{ "rx_alignment_errors",	NFP_MAC_STATS_RX_ALIGNMENT_ERRORS, },
84098ce840SJakub Kicinski 	{ "rx_pause_mac_ctrl_frames",
85098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PAUSE_MAC_CTRL_FRAMES, },
86098ce840SJakub Kicinski 	{ "rx_frames_received_ok",	NFP_MAC_STATS_RX_FRAMES_RECEIVED_OK, },
87098ce840SJakub Kicinski 	{ "rx_frame_check_sequence_errors",
88098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_FRAME_CHECK_SEQUENCE_ERRORS, },
89098ce840SJakub Kicinski 	{ "rx_unicast_pkts",		NFP_MAC_STATS_RX_UNICAST_PKTS, },
90098ce840SJakub Kicinski 	{ "rx_multicast_pkts",		NFP_MAC_STATS_RX_MULTICAST_PKTS, },
91098ce840SJakub Kicinski 	{ "rx_pkts",			NFP_MAC_STATS_RX_PKTS, },
92098ce840SJakub Kicinski 	{ "rx_undersize_pkts",		NFP_MAC_STATS_RX_UNDERSIZE_PKTS, },
93098ce840SJakub Kicinski 	{ "rx_pkts_64_octets",		NFP_MAC_STATS_RX_PKTS_64_OCTETS, },
94098ce840SJakub Kicinski 	{ "rx_pkts_65_to_127_octets",
95098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PKTS_65_TO_127_OCTETS, },
96098ce840SJakub Kicinski 	{ "rx_pkts_128_to_255_octets",
97098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PKTS_128_TO_255_OCTETS, },
98098ce840SJakub Kicinski 	{ "rx_pkts_256_to_511_octets",
99098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PKTS_256_TO_511_OCTETS, },
100098ce840SJakub Kicinski 	{ "rx_pkts_512_to_1023_octets",
101098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PKTS_512_TO_1023_OCTETS, },
102098ce840SJakub Kicinski 	{ "rx_pkts_1024_to_1518_octets",
103098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PKTS_1024_TO_1518_OCTETS, },
104098ce840SJakub Kicinski 	{ "rx_pkts_1519_to_max_octets",
105098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_PKTS_1519_TO_MAX_OCTETS, },
106098ce840SJakub Kicinski 	{ "rx_jabbers",			NFP_MAC_STATS_RX_JABBERS, },
107098ce840SJakub Kicinski 	{ "rx_fragments",		NFP_MAC_STATS_RX_FRAGMENTS, },
108098ce840SJakub Kicinski 	{ "rx_oversize_pkts",		NFP_MAC_STATS_RX_OVERSIZE_PKTS, },
109098ce840SJakub Kicinski 	{ "rx_pause_frames_class0",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS0, },
110098ce840SJakub Kicinski 	{ "rx_pause_frames_class1",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS1, },
111098ce840SJakub Kicinski 	{ "rx_pause_frames_class2",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS2, },
112098ce840SJakub Kicinski 	{ "rx_pause_frames_class3",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS3, },
113098ce840SJakub Kicinski 	{ "rx_pause_frames_class4",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS4, },
114098ce840SJakub Kicinski 	{ "rx_pause_frames_class5",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS5, },
115098ce840SJakub Kicinski 	{ "rx_pause_frames_class6",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS6, },
116098ce840SJakub Kicinski 	{ "rx_pause_frames_class7",	NFP_MAC_STATS_RX_PAUSE_FRAMES_CLASS7, },
117098ce840SJakub Kicinski 	{ "rx_mac_ctrl_frames_received",
118098ce840SJakub Kicinski 			NFP_MAC_STATS_RX_MAC_CTRL_FRAMES_RECEIVED, },
119098ce840SJakub Kicinski 	{ "rx_mac_head_drop",		NFP_MAC_STATS_RX_MAC_HEAD_DROP, },
120098ce840SJakub Kicinski 	{ "tx_queue_drop",		NFP_MAC_STATS_TX_QUEUE_DROP, },
121098ce840SJakub Kicinski 	{ "tx_octets",			NFP_MAC_STATS_TX_OUT_OCTETS, },
122098ce840SJakub Kicinski 	{ "tx_vlan_transmitted_ok",	NFP_MAC_STATS_TX_VLAN_TRANSMITTED_OK, },
123098ce840SJakub Kicinski 	{ "tx_errors",			NFP_MAC_STATS_TX_OUT_ERRORS, },
124098ce840SJakub Kicinski 	{ "tx_broadcast_pkts",		NFP_MAC_STATS_TX_BROADCAST_PKTS, },
125098ce840SJakub Kicinski 	{ "tx_pause_mac_ctrl_frames",
126098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PAUSE_MAC_CTRL_FRAMES, },
127098ce840SJakub Kicinski 	{ "tx_frames_transmitted_ok",
128098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_FRAMES_TRANSMITTED_OK, },
129098ce840SJakub Kicinski 	{ "tx_unicast_pkts",		NFP_MAC_STATS_TX_UNICAST_PKTS, },
130098ce840SJakub Kicinski 	{ "tx_multicast_pkts",		NFP_MAC_STATS_TX_MULTICAST_PKTS, },
131098ce840SJakub Kicinski 	{ "tx_pkts_64_octets",		NFP_MAC_STATS_TX_PKTS_64_OCTETS, },
132098ce840SJakub Kicinski 	{ "tx_pkts_65_to_127_octets",
133098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PKTS_65_TO_127_OCTETS, },
134098ce840SJakub Kicinski 	{ "tx_pkts_128_to_255_octets",
135098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PKTS_128_TO_255_OCTETS, },
136098ce840SJakub Kicinski 	{ "tx_pkts_256_to_511_octets",
137098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PKTS_256_TO_511_OCTETS, },
138098ce840SJakub Kicinski 	{ "tx_pkts_512_to_1023_octets",
139098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PKTS_512_TO_1023_OCTETS, },
140098ce840SJakub Kicinski 	{ "tx_pkts_1024_to_1518_octets",
141098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PKTS_1024_TO_1518_OCTETS, },
142098ce840SJakub Kicinski 	{ "tx_pkts_1519_to_max_octets",
143098ce840SJakub Kicinski 			NFP_MAC_STATS_TX_PKTS_1519_TO_MAX_OCTETS, },
144098ce840SJakub Kicinski 	{ "tx_pause_frames_class0",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS0, },
145098ce840SJakub Kicinski 	{ "tx_pause_frames_class1",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS1, },
146098ce840SJakub Kicinski 	{ "tx_pause_frames_class2",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS2, },
147098ce840SJakub Kicinski 	{ "tx_pause_frames_class3",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS3, },
148098ce840SJakub Kicinski 	{ "tx_pause_frames_class4",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS4, },
149098ce840SJakub Kicinski 	{ "tx_pause_frames_class5",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS5, },
150098ce840SJakub Kicinski 	{ "tx_pause_frames_class6",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS6, },
151098ce840SJakub Kicinski 	{ "tx_pause_frames_class7",	NFP_MAC_STATS_TX_PAUSE_FRAMES_CLASS7, },
152098ce840SJakub Kicinski };
153098ce840SJakub Kicinski 
154ca866ee8SJakub Kicinski static const char nfp_tlv_stat_names[][ETH_GSTRING_LEN] = {
155ca866ee8SJakub Kicinski 	[1]	= "dev_rx_discards",
156ca866ee8SJakub Kicinski 	[2]	= "dev_rx_errors",
157ca866ee8SJakub Kicinski 	[3]	= "dev_rx_bytes",
158ca866ee8SJakub Kicinski 	[4]	= "dev_rx_uc_bytes",
159ca866ee8SJakub Kicinski 	[5]	= "dev_rx_mc_bytes",
160ca866ee8SJakub Kicinski 	[6]	= "dev_rx_bc_bytes",
161ca866ee8SJakub Kicinski 	[7]	= "dev_rx_pkts",
162ca866ee8SJakub Kicinski 	[8]	= "dev_rx_mc_pkts",
163ca866ee8SJakub Kicinski 	[9]	= "dev_rx_bc_pkts",
164ca866ee8SJakub Kicinski 
165ca866ee8SJakub Kicinski 	[10]	= "dev_tx_discards",
166ca866ee8SJakub Kicinski 	[11]	= "dev_tx_errors",
167ca866ee8SJakub Kicinski 	[12]	= "dev_tx_bytes",
168ca866ee8SJakub Kicinski 	[13]	= "dev_tx_uc_bytes",
169ca866ee8SJakub Kicinski 	[14]	= "dev_tx_mc_bytes",
170ca866ee8SJakub Kicinski 	[15]	= "dev_tx_bc_bytes",
171ca866ee8SJakub Kicinski 	[16]	= "dev_tx_pkts",
172ca866ee8SJakub Kicinski 	[17]	= "dev_tx_mc_pkts",
173ca866ee8SJakub Kicinski 	[18]	= "dev_tx_bc_pkts",
174ca866ee8SJakub Kicinski };
175ca866ee8SJakub Kicinski 
1764c352362SJakub Kicinski #define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats)
177899a37adSJakub Kicinski #define NN_ET_SWITCH_STATS_LEN 9
1785bcb5c7eSDirk van der Merwe #define NN_RVEC_GATHER_STATS	13
17918f76191SJakub Kicinski #define NN_RVEC_PER_Q_STATS	3
1806a35ddc5SJakub Kicinski #define NN_CTRL_PATH_STATS	4
1814c352362SJakub Kicinski 
18261f7c6f4SDirk van der Merwe #define SFP_SFF_REV_COMPLIANCE	1
18361f7c6f4SDirk van der Merwe 
nfp_net_get_nspinfo(struct nfp_app * app,char * version)1847ac9ebd5SJakub Kicinski static void nfp_net_get_nspinfo(struct nfp_app *app, char *version)
185bd5ca062SJakub Kicinski {
186bd5ca062SJakub Kicinski 	struct nfp_nsp *nsp;
187bd5ca062SJakub Kicinski 
1887ac9ebd5SJakub Kicinski 	if (!app)
189bd5ca062SJakub Kicinski 		return;
190bd5ca062SJakub Kicinski 
1917ac9ebd5SJakub Kicinski 	nsp = nfp_nsp_open(app->cpp);
192bd5ca062SJakub Kicinski 	if (IS_ERR(nsp))
193bd5ca062SJakub Kicinski 		return;
194bd5ca062SJakub Kicinski 
1959e4c2cfcSJakub Kicinski 	snprintf(version, ETHTOOL_FWVERS_LEN, "%hu.%hu",
196bd5ca062SJakub Kicinski 		 nfp_nsp_get_abi_ver_major(nsp),
197bd5ca062SJakub Kicinski 		 nfp_nsp_get_abi_ver_minor(nsp));
198bd5ca062SJakub Kicinski 
199bd5ca062SJakub Kicinski 	nfp_nsp_close(nsp);
200bd5ca062SJakub Kicinski }
201bd5ca062SJakub Kicinski 
2029e4c2cfcSJakub Kicinski static void
nfp_get_drvinfo(struct nfp_app * app,struct pci_dev * pdev,const char * vnic_version,struct ethtool_drvinfo * drvinfo)2039e4c2cfcSJakub Kicinski nfp_get_drvinfo(struct nfp_app *app, struct pci_dev *pdev,
2049e4c2cfcSJakub Kicinski 		const char *vnic_version, struct ethtool_drvinfo *drvinfo)
2054c352362SJakub Kicinski {
206bd5ca062SJakub Kicinski 	char nsp_version[ETHTOOL_FWVERS_LEN] = {};
2074c352362SJakub Kicinski 
208f029c781SWolfram Sang 	strscpy(drvinfo->driver, dev_driver_string(&pdev->dev),
209230b1e54SUwe Kleine-König 		sizeof(drvinfo->driver));
2109e4c2cfcSJakub Kicinski 	nfp_net_get_nspinfo(app, nsp_version);
2114c352362SJakub Kicinski 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
2129e4c2cfcSJakub Kicinski 		 "%s %s %s %s", vnic_version, nsp_version,
2139e4c2cfcSJakub Kicinski 		 nfp_app_mip_name(app), nfp_app_name(app));
2149e4c2cfcSJakub Kicinski }
2159e4c2cfcSJakub Kicinski 
2169e4c2cfcSJakub Kicinski static void
nfp_net_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)2179e4c2cfcSJakub Kicinski nfp_net_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
2189e4c2cfcSJakub Kicinski {
2199e4c2cfcSJakub Kicinski 	char vnic_version[ETHTOOL_FWVERS_LEN] = {};
2209e4c2cfcSJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
2219e4c2cfcSJakub Kicinski 
2229e4c2cfcSJakub Kicinski 	snprintf(vnic_version, sizeof(vnic_version), "%d.%d.%d.%d",
223d9e3c299SJakub Kicinski 		 nn->fw_ver.extend, nn->fw_ver.class,
2249e4c2cfcSJakub Kicinski 		 nn->fw_ver.major, nn->fw_ver.minor);
225f029c781SWolfram Sang 	strscpy(drvinfo->bus_info, pci_name(nn->pdev),
2264c352362SJakub Kicinski 		sizeof(drvinfo->bus_info));
2274c352362SJakub Kicinski 
2289e4c2cfcSJakub Kicinski 	nfp_get_drvinfo(nn->app, nn->pdev, vnic_version, drvinfo);
2299e4c2cfcSJakub Kicinski }
2309e4c2cfcSJakub Kicinski 
2312820a400SFei Qin static int
nfp_net_nway_reset(struct net_device * netdev)2322820a400SFei Qin nfp_net_nway_reset(struct net_device *netdev)
2332820a400SFei Qin {
2342820a400SFei Qin 	struct nfp_eth_table_port *eth_port;
2352820a400SFei Qin 	struct nfp_port *port;
2362820a400SFei Qin 	int err;
2372820a400SFei Qin 
2382820a400SFei Qin 	port = nfp_port_from_netdev(netdev);
2392820a400SFei Qin 	eth_port = nfp_port_get_eth_port(port);
2402820a400SFei Qin 	if (!eth_port)
2412820a400SFei Qin 		return -EOPNOTSUPP;
2422820a400SFei Qin 
2432820a400SFei Qin 	if (!netif_running(netdev))
2442820a400SFei Qin 		return 0;
2452820a400SFei Qin 
2462820a400SFei Qin 	err = nfp_eth_set_configured(port->app->cpp, eth_port->index, false);
2472820a400SFei Qin 	if (err) {
2482820a400SFei Qin 		netdev_info(netdev, "Link down failed: %d\n", err);
2492820a400SFei Qin 		return err;
2502820a400SFei Qin 	}
2512820a400SFei Qin 
2522820a400SFei Qin 	err = nfp_eth_set_configured(port->app->cpp, eth_port->index, true);
2532820a400SFei Qin 	if (err) {
2542820a400SFei Qin 		netdev_info(netdev, "Link up failed: %d\n", err);
2552820a400SFei Qin 		return err;
2562820a400SFei Qin 	}
2572820a400SFei Qin 
2582820a400SFei Qin 	netdev_info(netdev, "Link reset succeeded\n");
2592820a400SFei Qin 	return 0;
2602820a400SFei Qin }
2612820a400SFei Qin 
2629e4c2cfcSJakub Kicinski static void
nfp_app_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)2639e4c2cfcSJakub Kicinski nfp_app_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
2649e4c2cfcSJakub Kicinski {
2655d4b0b40SJakub Kicinski 	struct nfp_app *app = nfp_app_from_netdev(netdev);
2669e4c2cfcSJakub Kicinski 
267f029c781SWolfram Sang 	strscpy(drvinfo->bus_info, pci_name(app->pdev),
2685d4b0b40SJakub Kicinski 		sizeof(drvinfo->bus_info));
2699e4c2cfcSJakub Kicinski 	nfp_get_drvinfo(app, app->pdev, "*", drvinfo);
2704c352362SJakub Kicinski }
2714c352362SJakub Kicinski 
2720d087093SDirk van der Merwe static void
nfp_net_set_fec_link_mode(struct nfp_eth_table_port * eth_port,struct ethtool_link_ksettings * c)2730d087093SDirk van der Merwe nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port,
2740d087093SDirk van der Merwe 			  struct ethtool_link_ksettings *c)
2750d087093SDirk van der Merwe {
2760d087093SDirk van der Merwe 	unsigned int modes;
2770d087093SDirk van der Merwe 
2780d087093SDirk van der Merwe 	ethtool_link_ksettings_add_link_mode(c, supported, FEC_NONE);
2790d087093SDirk van der Merwe 	if (!nfp_eth_can_support_fec(eth_port)) {
2800d087093SDirk van der Merwe 		ethtool_link_ksettings_add_link_mode(c, advertising, FEC_NONE);
2810d087093SDirk van der Merwe 		return;
2820d087093SDirk van der Merwe 	}
2830d087093SDirk van der Merwe 
2840d087093SDirk van der Merwe 	modes = nfp_eth_supported_fec_modes(eth_port);
2850d087093SDirk van der Merwe 	if (modes & NFP_FEC_BASER) {
2860d087093SDirk van der Merwe 		ethtool_link_ksettings_add_link_mode(c, supported, FEC_BASER);
2870d087093SDirk van der Merwe 		ethtool_link_ksettings_add_link_mode(c, advertising, FEC_BASER);
2880d087093SDirk van der Merwe 	}
2890d087093SDirk van der Merwe 
2900d087093SDirk van der Merwe 	if (modes & NFP_FEC_REED_SOLOMON) {
2910d087093SDirk van der Merwe 		ethtool_link_ksettings_add_link_mode(c, supported, FEC_RS);
2920d087093SDirk van der Merwe 		ethtool_link_ksettings_add_link_mode(c, advertising, FEC_RS);
2930d087093SDirk van der Merwe 	}
2940d087093SDirk van der Merwe }
2950d087093SDirk van der Merwe 
296821de68cSYu Xiao static const struct nfp_eth_media_link_mode {
297821de68cSYu Xiao 	u16 ethtool_link_mode;
298821de68cSYu Xiao 	u16 speed;
299821de68cSYu Xiao } nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = {
300821de68cSYu Xiao 	[NFP_MEDIA_1000BASE_CX] = {
301821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
302821de68cSYu Xiao 		.speed			= NFP_SPEED_1G,
303821de68cSYu Xiao 	},
304821de68cSYu Xiao 	[NFP_MEDIA_1000BASE_KX] = {
305821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
306821de68cSYu Xiao 		.speed			= NFP_SPEED_1G,
307821de68cSYu Xiao 	},
308821de68cSYu Xiao 	[NFP_MEDIA_10GBASE_KX4] = {
309821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
310821de68cSYu Xiao 		.speed			= NFP_SPEED_10G,
311821de68cSYu Xiao 	},
312821de68cSYu Xiao 	[NFP_MEDIA_10GBASE_KR] = {
313821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
314821de68cSYu Xiao 		.speed			= NFP_SPEED_10G,
315821de68cSYu Xiao 	},
316170677feSYu Xiao 	[NFP_MEDIA_10GBASE_LR] = {
317170677feSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
318170677feSYu Xiao 		.speed			= NFP_SPEED_10G,
319170677feSYu Xiao 	},
320821de68cSYu Xiao 	[NFP_MEDIA_10GBASE_CX4] = {
321821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
322821de68cSYu Xiao 		.speed			= NFP_SPEED_10G,
323821de68cSYu Xiao 	},
324821de68cSYu Xiao 	[NFP_MEDIA_10GBASE_CR] = {
325821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
326821de68cSYu Xiao 		.speed			= NFP_SPEED_10G,
327821de68cSYu Xiao 	},
328821de68cSYu Xiao 	[NFP_MEDIA_10GBASE_SR] = {
329821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
330821de68cSYu Xiao 		.speed			= NFP_SPEED_10G,
331821de68cSYu Xiao 	},
332821de68cSYu Xiao 	[NFP_MEDIA_10GBASE_ER] = {
333821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
334821de68cSYu Xiao 		.speed			= NFP_SPEED_10G,
335821de68cSYu Xiao 	},
336821de68cSYu Xiao 	[NFP_MEDIA_25GBASE_KR] = {
337821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
338821de68cSYu Xiao 		.speed			= NFP_SPEED_25G,
339821de68cSYu Xiao 	},
340821de68cSYu Xiao 	[NFP_MEDIA_25GBASE_KR_S] = {
341821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
342821de68cSYu Xiao 		.speed			= NFP_SPEED_25G,
343821de68cSYu Xiao 	},
344821de68cSYu Xiao 	[NFP_MEDIA_25GBASE_CR] = {
345821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
346821de68cSYu Xiao 		.speed			= NFP_SPEED_25G,
347821de68cSYu Xiao 	},
348821de68cSYu Xiao 	[NFP_MEDIA_25GBASE_CR_S] = {
349821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
350821de68cSYu Xiao 		.speed			= NFP_SPEED_25G,
351821de68cSYu Xiao 	},
352821de68cSYu Xiao 	[NFP_MEDIA_25GBASE_SR] = {
353821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
354821de68cSYu Xiao 		.speed			= NFP_SPEED_25G,
355821de68cSYu Xiao 	},
356170677feSYu Xiao 	[NFP_MEDIA_25GBASE_LR] = {
357170677feSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
358170677feSYu Xiao 		.speed			= NFP_SPEED_25G,
359170677feSYu Xiao 	},
360170677feSYu Xiao 	[NFP_MEDIA_25GBASE_ER] = {
361170677feSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
362170677feSYu Xiao 		.speed			= NFP_SPEED_25G,
363170677feSYu Xiao 	},
364821de68cSYu Xiao 	[NFP_MEDIA_40GBASE_CR4] = {
365821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
366821de68cSYu Xiao 		.speed			= NFP_SPEED_40G,
367821de68cSYu Xiao 	},
368821de68cSYu Xiao 	[NFP_MEDIA_40GBASE_KR4] = {
369821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
370821de68cSYu Xiao 		.speed			= NFP_SPEED_40G,
371821de68cSYu Xiao 	},
372821de68cSYu Xiao 	[NFP_MEDIA_40GBASE_SR4] = {
373821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
374821de68cSYu Xiao 		.speed			= NFP_SPEED_40G,
375821de68cSYu Xiao 	},
376821de68cSYu Xiao 	[NFP_MEDIA_40GBASE_LR4] = {
377821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
378821de68cSYu Xiao 		.speed			= NFP_SPEED_40G,
379821de68cSYu Xiao 	},
380821de68cSYu Xiao 	[NFP_MEDIA_50GBASE_KR] = {
381821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
382821de68cSYu Xiao 		.speed			= NFP_SPEED_50G,
383821de68cSYu Xiao 	},
384821de68cSYu Xiao 	[NFP_MEDIA_50GBASE_SR] = {
385821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
386821de68cSYu Xiao 		.speed			= NFP_SPEED_50G,
387821de68cSYu Xiao 	},
388821de68cSYu Xiao 	[NFP_MEDIA_50GBASE_CR] = {
389821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
390821de68cSYu Xiao 		.speed			= NFP_SPEED_50G,
391821de68cSYu Xiao 	},
392821de68cSYu Xiao 	[NFP_MEDIA_50GBASE_LR] = {
393821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
394821de68cSYu Xiao 		.speed			= NFP_SPEED_50G,
395821de68cSYu Xiao 	},
396821de68cSYu Xiao 	[NFP_MEDIA_50GBASE_ER] = {
397821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
398821de68cSYu Xiao 		.speed			= NFP_SPEED_50G,
399821de68cSYu Xiao 	},
400821de68cSYu Xiao 	[NFP_MEDIA_50GBASE_FR] = {
401821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
402821de68cSYu Xiao 		.speed			= NFP_SPEED_50G,
403821de68cSYu Xiao 	},
404821de68cSYu Xiao 	[NFP_MEDIA_100GBASE_KR4] = {
405821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
406821de68cSYu Xiao 		.speed			= NFP_SPEED_100G,
407821de68cSYu Xiao 	},
408821de68cSYu Xiao 	[NFP_MEDIA_100GBASE_SR4] = {
409821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
410821de68cSYu Xiao 		.speed			= NFP_SPEED_100G,
411821de68cSYu Xiao 	},
412821de68cSYu Xiao 	[NFP_MEDIA_100GBASE_CR4] = {
413821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
414821de68cSYu Xiao 		.speed			= NFP_SPEED_100G,
415821de68cSYu Xiao 	},
416821de68cSYu Xiao 	[NFP_MEDIA_100GBASE_KP4] = {
417821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
418821de68cSYu Xiao 		.speed			= NFP_SPEED_100G,
419821de68cSYu Xiao 	},
420821de68cSYu Xiao 	[NFP_MEDIA_100GBASE_CR10] = {
421821de68cSYu Xiao 		.ethtool_link_mode	= ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
422821de68cSYu Xiao 		.speed			= NFP_SPEED_100G,
423821de68cSYu Xiao 	},
424821de68cSYu Xiao };
425821de68cSYu Xiao 
426821de68cSYu Xiao static const unsigned int nfp_eth_speed_map[NFP_SUP_SPEED_NUMBER] = {
427821de68cSYu Xiao 	[NFP_SPEED_1G]		= SPEED_1000,
428821de68cSYu Xiao 	[NFP_SPEED_10G]		= SPEED_10000,
429821de68cSYu Xiao 	[NFP_SPEED_25G]		= SPEED_25000,
430821de68cSYu Xiao 	[NFP_SPEED_40G]		= SPEED_40000,
431821de68cSYu Xiao 	[NFP_SPEED_50G]		= SPEED_50000,
432821de68cSYu Xiao 	[NFP_SPEED_100G]	= SPEED_100000,
433a61474c4SYu Xiao };
434a61474c4SYu Xiao 
nfp_add_media_link_mode(struct nfp_port * port,struct nfp_eth_table_port * eth_port,struct ethtool_link_ksettings * cmd)435a61474c4SYu Xiao static void nfp_add_media_link_mode(struct nfp_port *port,
436a61474c4SYu Xiao 				    struct nfp_eth_table_port *eth_port,
437a61474c4SYu Xiao 				    struct ethtool_link_ksettings *cmd)
438a61474c4SYu Xiao {
439821de68cSYu Xiao 	bitmap_zero(port->speed_bitmap, NFP_SUP_SPEED_NUMBER);
440a61474c4SYu Xiao 
441a61474c4SYu Xiao 	for (u32 i = 0; i < NFP_MEDIA_LINK_MODES_NUMBER; i++) {
442a61474c4SYu Xiao 		if (i < 64) {
443*a731a43eSYinjun Zhang 			if (eth_port->link_modes_supp[0] & BIT_ULL(i)) {
444821de68cSYu Xiao 				__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
445a61474c4SYu Xiao 					  cmd->link_modes.supported);
446821de68cSYu Xiao 				__set_bit(nfp_eth_media_table[i].speed,
447821de68cSYu Xiao 					  port->speed_bitmap);
448821de68cSYu Xiao 			}
449a61474c4SYu Xiao 
450*a731a43eSYinjun Zhang 			if (eth_port->link_modes_ad[0] & BIT_ULL(i))
451821de68cSYu Xiao 				__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
452a61474c4SYu Xiao 					  cmd->link_modes.advertising);
453a61474c4SYu Xiao 		} else {
454*a731a43eSYinjun Zhang 			if (eth_port->link_modes_supp[1] & BIT_ULL(i - 64)) {
455821de68cSYu Xiao 				__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
456a61474c4SYu Xiao 					  cmd->link_modes.supported);
457821de68cSYu Xiao 				__set_bit(nfp_eth_media_table[i].speed,
458821de68cSYu Xiao 					  port->speed_bitmap);
459821de68cSYu Xiao 			}
460a61474c4SYu Xiao 
461*a731a43eSYinjun Zhang 			if (eth_port->link_modes_ad[1] & BIT_ULL(i - 64))
462821de68cSYu Xiao 				__set_bit(nfp_eth_media_table[i].ethtool_link_mode,
463a61474c4SYu Xiao 					  cmd->link_modes.advertising);
464a61474c4SYu Xiao 		}
465a61474c4SYu Xiao 	}
466*a731a43eSYinjun Zhang 
467*a731a43eSYinjun Zhang 	/* We take all speeds as supported when it fails to read
468*a731a43eSYinjun Zhang 	 * link modes due to old management firmware that doesn't
469*a731a43eSYinjun Zhang 	 * support link modes reading or error occurring, so that
470*a731a43eSYinjun Zhang 	 * speed change of this port is allowed.
471*a731a43eSYinjun Zhang 	 */
472*a731a43eSYinjun Zhang 	if (bitmap_empty(port->speed_bitmap, NFP_SUP_SPEED_NUMBER))
473*a731a43eSYinjun Zhang 		bitmap_fill(port->speed_bitmap, NFP_SUP_SPEED_NUMBER);
474a61474c4SYu Xiao }
475a61474c4SYu Xiao 
476265aeb51SJakub Kicinski /**
477265aeb51SJakub Kicinski  * nfp_net_get_link_ksettings - Get Link Speed settings
478265aeb51SJakub Kicinski  * @netdev:	network interface device structure
479265aeb51SJakub Kicinski  * @cmd:	ethtool command
480265aeb51SJakub Kicinski  *
481265aeb51SJakub Kicinski  * Reports speed settings based on info in the BAR provided by the fw.
482265aeb51SJakub Kicinski  */
483265aeb51SJakub Kicinski static int
nfp_net_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)484265aeb51SJakub Kicinski nfp_net_get_link_ksettings(struct net_device *netdev,
485265aeb51SJakub Kicinski 			   struct ethtool_link_ksettings *cmd)
486265aeb51SJakub Kicinski {
487eb488c26SJakub Kicinski 	struct nfp_eth_table_port *eth_port;
488eb488c26SJakub Kicinski 	struct nfp_port *port;
489eb488c26SJakub Kicinski 	struct nfp_net *nn;
49062fad9e6SYinjun Zhang 	unsigned int speed;
49162fad9e6SYinjun Zhang 	u16 sts;
492265aeb51SJakub Kicinski 
493eb488c26SJakub Kicinski 	/* Init to unknowns */
494a61474c4SYu Xiao 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
495a61474c4SYu Xiao 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
496265aeb51SJakub Kicinski 	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
497265aeb51SJakub Kicinski 	cmd->base.port = PORT_OTHER;
498265aeb51SJakub Kicinski 	cmd->base.speed = SPEED_UNKNOWN;
499265aeb51SJakub Kicinski 	cmd->base.duplex = DUPLEX_UNKNOWN;
500265aeb51SJakub Kicinski 
501eb488c26SJakub Kicinski 	port = nfp_port_from_netdev(netdev);
5021876749dSJakub Kicinski 	eth_port = nfp_port_get_eth_port(port);
5030d087093SDirk van der Merwe 	if (eth_port) {
5040649e4d6SYu Xiao 		ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
5050649e4d6SYu Xiao 		ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
506a61474c4SYu Xiao 		nfp_add_media_link_mode(port, eth_port, cmd);
5078d545385SYinjun Zhang 		if (eth_port->supp_aneg) {
5088d545385SYinjun Zhang 			ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
5098d545385SYinjun Zhang 			if (eth_port->aneg == NFP_ANEG_AUTO) {
5108d545385SYinjun Zhang 				ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
5118d545385SYinjun Zhang 				cmd->base.autoneg = AUTONEG_ENABLE;
5128d545385SYinjun Zhang 			}
5138d545385SYinjun Zhang 		}
5140d087093SDirk van der Merwe 		nfp_net_set_fec_link_mode(eth_port, cmd);
5150d087093SDirk van der Merwe 	}
51642b1e6aaSJakub Kicinski 
517265aeb51SJakub Kicinski 	if (!netif_carrier_ok(netdev))
518265aeb51SJakub Kicinski 		return 0;
519265aeb51SJakub Kicinski 
52021d529d5SJakub Kicinski 	/* Use link speed from ETH table if available, otherwise try the BAR */
521eb488c26SJakub Kicinski 	if (eth_port) {
522eb488c26SJakub Kicinski 		cmd->base.port = eth_port->port_type;
523eb488c26SJakub Kicinski 		cmd->base.speed = eth_port->speed;
52421d529d5SJakub Kicinski 		cmd->base.duplex = DUPLEX_FULL;
52521d529d5SJakub Kicinski 		return 0;
52621d529d5SJakub Kicinski 	}
52721d529d5SJakub Kicinski 
5286d4f8cbaSJakub Kicinski 	if (!nfp_netdev_is_nfp_net(netdev))
5296d4f8cbaSJakub Kicinski 		return -EOPNOTSUPP;
5306d4f8cbaSJakub Kicinski 	nn = netdev_priv(netdev);
5316d4f8cbaSJakub Kicinski 
53262fad9e6SYinjun Zhang 	sts = nn_readw(nn, NFP_NET_CFG_STS);
53362fad9e6SYinjun Zhang 	speed = nfp_net_lr2speed(FIELD_GET(NFP_NET_CFG_STS_LINK_RATE, sts));
53462fad9e6SYinjun Zhang 	if (!speed)
535265aeb51SJakub Kicinski 		return -EOPNOTSUPP;
536265aeb51SJakub Kicinski 
53762fad9e6SYinjun Zhang 	if (speed != SPEED_UNKNOWN) {
53862fad9e6SYinjun Zhang 		cmd->base.speed = speed;
539265aeb51SJakub Kicinski 		cmd->base.duplex = DUPLEX_FULL;
54062fad9e6SYinjun Zhang 	}
541265aeb51SJakub Kicinski 
542265aeb51SJakub Kicinski 	return 0;
543265aeb51SJakub Kicinski }
544265aeb51SJakub Kicinski 
5457c698737SJakub Kicinski static int
nfp_net_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * cmd)5467c698737SJakub Kicinski nfp_net_set_link_ksettings(struct net_device *netdev,
5477c698737SJakub Kicinski 			   const struct ethtool_link_ksettings *cmd)
5487c698737SJakub Kicinski {
5498d545385SYinjun Zhang 	bool req_aneg = (cmd->base.autoneg == AUTONEG_ENABLE);
550eb488c26SJakub Kicinski 	struct nfp_eth_table_port *eth_port;
551eb488c26SJakub Kicinski 	struct nfp_port *port;
5527c698737SJakub Kicinski 	struct nfp_nsp *nsp;
5537c698737SJakub Kicinski 	int err;
5547c698737SJakub Kicinski 
555eb488c26SJakub Kicinski 	port = nfp_port_from_netdev(netdev);
556eb488c26SJakub Kicinski 	eth_port = __nfp_port_get_eth_port(port);
557eb488c26SJakub Kicinski 	if (!eth_port)
5587c698737SJakub Kicinski 		return -EOPNOTSUPP;
5597c698737SJakub Kicinski 
5607c698737SJakub Kicinski 	if (netif_running(netdev)) {
5617717c319SJakub Kicinski 		netdev_warn(netdev, "Changing settings not allowed on an active interface. It may cause the port to be disabled until driver reload.\n");
5627c698737SJakub Kicinski 		return -EBUSY;
5637c698737SJakub Kicinski 	}
5647c698737SJakub Kicinski 
565eb488c26SJakub Kicinski 	nsp = nfp_eth_config_start(port->app->cpp, eth_port->index);
5667c698737SJakub Kicinski 	if (IS_ERR(nsp))
5677c698737SJakub Kicinski 		return PTR_ERR(nsp);
5687c698737SJakub Kicinski 
5698d545385SYinjun Zhang 	if (req_aneg && !eth_port->supp_aneg) {
5708d545385SYinjun Zhang 		netdev_warn(netdev, "Autoneg is not supported.\n");
5718d545385SYinjun Zhang 		err = -EOPNOTSUPP;
5728d545385SYinjun Zhang 		goto err_bad_set;
5738d545385SYinjun Zhang 	}
5748d545385SYinjun Zhang 
5758d545385SYinjun Zhang 	err = __nfp_eth_set_aneg(nsp, req_aneg ? NFP_ANEG_AUTO : NFP_ANEG_DISABLED);
5767c698737SJakub Kicinski 	if (err)
5777c698737SJakub Kicinski 		goto err_bad_set;
5788d545385SYinjun Zhang 
5797c698737SJakub Kicinski 	if (cmd->base.speed != SPEED_UNKNOWN) {
580eb488c26SJakub Kicinski 		u32 speed = cmd->base.speed / eth_port->lanes;
581821de68cSYu Xiao 		bool is_supported = false;
582821de68cSYu Xiao 
583821de68cSYu Xiao 		for (u32 i = 0; i < NFP_SUP_SPEED_NUMBER; i++) {
584821de68cSYu Xiao 			if (cmd->base.speed == nfp_eth_speed_map[i] &&
585821de68cSYu Xiao 			    test_bit(i, port->speed_bitmap)) {
586821de68cSYu Xiao 				is_supported = true;
587821de68cSYu Xiao 				break;
588821de68cSYu Xiao 			}
589821de68cSYu Xiao 		}
590821de68cSYu Xiao 
591821de68cSYu Xiao 		if (!is_supported) {
592821de68cSYu Xiao 			netdev_err(netdev, "Speed %u is not supported.\n",
593821de68cSYu Xiao 				   cmd->base.speed);
594821de68cSYu Xiao 			err = -EINVAL;
595821de68cSYu Xiao 			goto err_bad_set;
596821de68cSYu Xiao 		}
5977c698737SJakub Kicinski 
5988d545385SYinjun Zhang 		if (req_aneg) {
5998d545385SYinjun Zhang 			netdev_err(netdev, "Speed changing is not allowed when working on autoneg mode.\n");
6008d545385SYinjun Zhang 			err = -EINVAL;
6018d545385SYinjun Zhang 			goto err_bad_set;
6028d545385SYinjun Zhang 		}
6038d545385SYinjun Zhang 
6047c698737SJakub Kicinski 		err = __nfp_eth_set_speed(nsp, speed);
6057c698737SJakub Kicinski 		if (err)
6067c698737SJakub Kicinski 			goto err_bad_set;
6077c698737SJakub Kicinski 	}
6087c698737SJakub Kicinski 
6097c698737SJakub Kicinski 	err = nfp_eth_config_commit_end(nsp);
6107c698737SJakub Kicinski 	if (err > 0)
6117c698737SJakub Kicinski 		return 0; /* no change */
6127c698737SJakub Kicinski 
613eb488c26SJakub Kicinski 	nfp_net_refresh_port_table(port);
6147c698737SJakub Kicinski 
6157c698737SJakub Kicinski 	return err;
6167c698737SJakub Kicinski 
6177c698737SJakub Kicinski err_bad_set:
6187c698737SJakub Kicinski 	nfp_eth_config_cleanup_end(nsp);
6197c698737SJakub Kicinski 	return err;
6207c698737SJakub Kicinski }
6217c698737SJakub Kicinski 
nfp_net_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)6224c352362SJakub Kicinski static void nfp_net_get_ringparam(struct net_device *netdev,
62374624944SHao Chen 				  struct ethtool_ringparam *ring,
62474624944SHao Chen 				  struct kernel_ethtool_ringparam *kernel_ring,
62574624944SHao Chen 				  struct netlink_ext_ack *extack)
6264c352362SJakub Kicinski {
6274c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
6287f3aa620SJakub Kicinski 	u32 qc_max = nn->dev_info->max_qc_size;
6294c352362SJakub Kicinski 
6307f3aa620SJakub Kicinski 	ring->rx_max_pending = qc_max;
631d6488c49SJakub Kicinski 	ring->tx_max_pending = qc_max / nn->dp.ops->tx_min_desc_per_pkt;
63279c12a75SJakub Kicinski 	ring->rx_pending = nn->dp.rxd_cnt;
63379c12a75SJakub Kicinski 	ring->tx_pending = nn->dp.txd_cnt;
6344c352362SJakub Kicinski }
6354c352362SJakub Kicinski 
nfp_net_set_ring_size(struct nfp_net * nn,u32 rxd_cnt,u32 txd_cnt)63668453c7aSJakub Kicinski static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
63768453c7aSJakub Kicinski {
638783496b0SJakub Kicinski 	struct nfp_net_dp *dp;
63968453c7aSJakub Kicinski 
640783496b0SJakub Kicinski 	dp = nfp_net_clone_dp(nn);
641783496b0SJakub Kicinski 	if (!dp)
642783496b0SJakub Kicinski 		return -ENOMEM;
643783496b0SJakub Kicinski 
644892a7f70SJakub Kicinski 	dp->rxd_cnt = rxd_cnt;
645892a7f70SJakub Kicinski 	dp->txd_cnt = txd_cnt;
646892a7f70SJakub Kicinski 
647d957c0f7SJakub Kicinski 	return nfp_net_ring_reconfig(nn, dp, NULL);
64868453c7aSJakub Kicinski }
64968453c7aSJakub Kicinski 
nfp_net_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)6504c352362SJakub Kicinski static int nfp_net_set_ringparam(struct net_device *netdev,
65174624944SHao Chen 				 struct ethtool_ringparam *ring,
65274624944SHao Chen 				 struct kernel_ethtool_ringparam *kernel_ring,
65374624944SHao Chen 				 struct netlink_ext_ack *extack)
6544c352362SJakub Kicinski {
655d6488c49SJakub Kicinski 	u32 tx_dpp, qc_min, qc_max, rxd_cnt, txd_cnt;
6564c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
6574c352362SJakub Kicinski 
6584c352362SJakub Kicinski 	/* We don't have separate queues/rings for small/large frames. */
6594c352362SJakub Kicinski 	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
6604c352362SJakub Kicinski 		return -EINVAL;
6614c352362SJakub Kicinski 
6627f3aa620SJakub Kicinski 	qc_min = nn->dev_info->min_qc_size;
6637f3aa620SJakub Kicinski 	qc_max = nn->dev_info->max_qc_size;
664d6488c49SJakub Kicinski 	tx_dpp = nn->dp.ops->tx_min_desc_per_pkt;
6654c352362SJakub Kicinski 	/* Round up to supported values */
6664c352362SJakub Kicinski 	rxd_cnt = roundup_pow_of_two(ring->rx_pending);
6674c352362SJakub Kicinski 	txd_cnt = roundup_pow_of_two(ring->tx_pending);
6684c352362SJakub Kicinski 
6697f3aa620SJakub Kicinski 	if (rxd_cnt < qc_min || rxd_cnt > qc_max ||
670d6488c49SJakub Kicinski 	    txd_cnt < qc_min / tx_dpp || txd_cnt > qc_max / tx_dpp)
671cc7c0333SJakub Kicinski 		return -EINVAL;
672cc7c0333SJakub Kicinski 
67379c12a75SJakub Kicinski 	if (nn->dp.rxd_cnt == rxd_cnt && nn->dp.txd_cnt == txd_cnt)
674cc7c0333SJakub Kicinski 		return 0;
675cc7c0333SJakub Kicinski 
6764c352362SJakub Kicinski 	nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n",
67779c12a75SJakub Kicinski 	       nn->dp.rxd_cnt, rxd_cnt, nn->dp.txd_cnt, txd_cnt);
6784c352362SJakub Kicinski 
679cc7c0333SJakub Kicinski 	return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt);
6804c352362SJakub Kicinski }
6814c352362SJakub Kicinski 
nfp_test_link(struct net_device * netdev)68215137daeSFei Qin static int nfp_test_link(struct net_device *netdev)
68315137daeSFei Qin {
68415137daeSFei Qin 	if (!netif_carrier_ok(netdev) || !(netdev->flags & IFF_UP))
68515137daeSFei Qin 		return 1;
68615137daeSFei Qin 
68715137daeSFei Qin 	return 0;
68815137daeSFei Qin }
68915137daeSFei Qin 
nfp_test_nsp(struct net_device * netdev)69015137daeSFei Qin static int nfp_test_nsp(struct net_device *netdev)
69115137daeSFei Qin {
69215137daeSFei Qin 	struct nfp_app *app = nfp_app_from_netdev(netdev);
69315137daeSFei Qin 	struct nfp_nsp_identify *nspi;
69415137daeSFei Qin 	struct nfp_nsp *nsp;
69515137daeSFei Qin 	int err;
69615137daeSFei Qin 
69715137daeSFei Qin 	nsp = nfp_nsp_open(app->cpp);
69815137daeSFei Qin 	if (IS_ERR(nsp)) {
69915137daeSFei Qin 		err = PTR_ERR(nsp);
70015137daeSFei Qin 		netdev_info(netdev, "NSP Test: failed to access the NSP: %d\n", err);
70115137daeSFei Qin 		goto exit;
70215137daeSFei Qin 	}
70315137daeSFei Qin 
70415137daeSFei Qin 	if (nfp_nsp_get_abi_ver_minor(nsp) < 15) {
70515137daeSFei Qin 		err = -EOPNOTSUPP;
70615137daeSFei Qin 		goto exit_close_nsp;
70715137daeSFei Qin 	}
70815137daeSFei Qin 
70915137daeSFei Qin 	nspi = kzalloc(sizeof(*nspi), GFP_KERNEL);
71015137daeSFei Qin 	if (!nspi) {
71115137daeSFei Qin 		err = -ENOMEM;
71215137daeSFei Qin 		goto exit_close_nsp;
71315137daeSFei Qin 	}
71415137daeSFei Qin 
71515137daeSFei Qin 	err = nfp_nsp_read_identify(nsp, nspi, sizeof(*nspi));
71615137daeSFei Qin 	if (err < 0)
71715137daeSFei Qin 		netdev_info(netdev, "NSP Test: reading bsp version failed %d\n", err);
71815137daeSFei Qin 
71915137daeSFei Qin 	kfree(nspi);
72015137daeSFei Qin exit_close_nsp:
72115137daeSFei Qin 	nfp_nsp_close(nsp);
72215137daeSFei Qin exit:
72315137daeSFei Qin 	return err;
72415137daeSFei Qin }
72515137daeSFei Qin 
nfp_test_fw(struct net_device * netdev)72615137daeSFei Qin static int nfp_test_fw(struct net_device *netdev)
72715137daeSFei Qin {
72815137daeSFei Qin 	struct nfp_net *nn = netdev_priv(netdev);
72915137daeSFei Qin 	int err;
73015137daeSFei Qin 
73115137daeSFei Qin 	err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN);
73215137daeSFei Qin 	if (err)
73315137daeSFei Qin 		netdev_info(netdev, "FW Test: update failed %d\n", err);
73415137daeSFei Qin 
73515137daeSFei Qin 	return err;
73615137daeSFei Qin }
73715137daeSFei Qin 
nfp_test_reg(struct net_device * netdev)73815137daeSFei Qin static int nfp_test_reg(struct net_device *netdev)
73915137daeSFei Qin {
74015137daeSFei Qin 	struct nfp_app *app = nfp_app_from_netdev(netdev);
74115137daeSFei Qin 	struct nfp_cpp *cpp = app->cpp;
74215137daeSFei Qin 	u32 model = nfp_cpp_model(cpp);
74315137daeSFei Qin 	u32 value;
74415137daeSFei Qin 	int err;
74515137daeSFei Qin 
74615137daeSFei Qin 	err = nfp_cpp_model_autodetect(cpp, &value);
74715137daeSFei Qin 	if (err < 0) {
74815137daeSFei Qin 		netdev_info(netdev, "REG Test: NFP model detection failed %d\n", err);
74915137daeSFei Qin 		return err;
75015137daeSFei Qin 	}
75115137daeSFei Qin 
75215137daeSFei Qin 	return (value == model) ? 0 : 1;
75315137daeSFei Qin }
75415137daeSFei Qin 
link_test_supported(struct net_device * netdev)75515137daeSFei Qin static bool link_test_supported(struct net_device *netdev)
75615137daeSFei Qin {
75715137daeSFei Qin 	return true;
75815137daeSFei Qin }
75915137daeSFei Qin 
nsp_test_supported(struct net_device * netdev)76015137daeSFei Qin static bool nsp_test_supported(struct net_device *netdev)
76115137daeSFei Qin {
76215137daeSFei Qin 	if (nfp_app_from_netdev(netdev))
76315137daeSFei Qin 		return true;
76415137daeSFei Qin 
76515137daeSFei Qin 	return false;
76615137daeSFei Qin }
76715137daeSFei Qin 
fw_test_supported(struct net_device * netdev)76815137daeSFei Qin static bool fw_test_supported(struct net_device *netdev)
76915137daeSFei Qin {
77015137daeSFei Qin 	if (nfp_netdev_is_nfp_net(netdev))
77115137daeSFei Qin 		return true;
77215137daeSFei Qin 
77315137daeSFei Qin 	return false;
77415137daeSFei Qin }
77515137daeSFei Qin 
reg_test_supported(struct net_device * netdev)77615137daeSFei Qin static bool reg_test_supported(struct net_device *netdev)
77715137daeSFei Qin {
77815137daeSFei Qin 	if (nfp_app_from_netdev(netdev))
77915137daeSFei Qin 		return true;
78015137daeSFei Qin 
78115137daeSFei Qin 	return false;
78215137daeSFei Qin }
78315137daeSFei Qin 
78415137daeSFei Qin static struct nfp_self_test_item {
78515137daeSFei Qin 	char name[ETH_GSTRING_LEN];
78615137daeSFei Qin 	bool (*is_supported)(struct net_device *dev);
78715137daeSFei Qin 	int (*func)(struct net_device *dev);
78815137daeSFei Qin } nfp_self_test[] = {
78915137daeSFei Qin 	{"Link Test", link_test_supported, nfp_test_link},
79015137daeSFei Qin 	{"NSP Test", nsp_test_supported, nfp_test_nsp},
79115137daeSFei Qin 	{"Firmware Test", fw_test_supported, nfp_test_fw},
79215137daeSFei Qin 	{"Register Test", reg_test_supported, nfp_test_reg}
79315137daeSFei Qin };
79415137daeSFei Qin 
79515137daeSFei Qin #define NFP_TEST_TOTAL_NUM ARRAY_SIZE(nfp_self_test)
79615137daeSFei Qin 
nfp_get_self_test_strings(struct net_device * netdev,u8 * data)79715137daeSFei Qin static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data)
79815137daeSFei Qin {
79915137daeSFei Qin 	int i;
80015137daeSFei Qin 
80115137daeSFei Qin 	for (i = 0; i < NFP_TEST_TOTAL_NUM; i++)
80215137daeSFei Qin 		if (nfp_self_test[i].is_supported(netdev))
80315137daeSFei Qin 			ethtool_sprintf(&data, nfp_self_test[i].name);
80415137daeSFei Qin }
80515137daeSFei Qin 
nfp_get_self_test_count(struct net_device * netdev)80615137daeSFei Qin static int nfp_get_self_test_count(struct net_device *netdev)
80715137daeSFei Qin {
80815137daeSFei Qin 	int i, count = 0;
80915137daeSFei Qin 
81015137daeSFei Qin 	for (i = 0; i < NFP_TEST_TOTAL_NUM; i++)
81115137daeSFei Qin 		if (nfp_self_test[i].is_supported(netdev))
81215137daeSFei Qin 			count++;
81315137daeSFei Qin 
81415137daeSFei Qin 	return count;
81515137daeSFei Qin }
81615137daeSFei Qin 
nfp_net_self_test(struct net_device * netdev,struct ethtool_test * eth_test,u64 * data)81715137daeSFei Qin static void nfp_net_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
81815137daeSFei Qin 			      u64 *data)
81915137daeSFei Qin {
82015137daeSFei Qin 	int i, ret, count = 0;
82115137daeSFei Qin 
82215137daeSFei Qin 	netdev_info(netdev, "Start self test\n");
82315137daeSFei Qin 
82415137daeSFei Qin 	for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) {
82515137daeSFei Qin 		if (nfp_self_test[i].is_supported(netdev)) {
82615137daeSFei Qin 			ret = nfp_self_test[i].func(netdev);
82715137daeSFei Qin 			if (ret)
82815137daeSFei Qin 				eth_test->flags |= ETH_TEST_FL_FAILED;
82915137daeSFei Qin 			data[count++] = ret;
83015137daeSFei Qin 		}
83115137daeSFei Qin 	}
83215137daeSFei Qin 
83315137daeSFei Qin 	netdev_info(netdev, "Test end\n");
83415137daeSFei Qin }
83515137daeSFei Qin 
nfp_vnic_get_sw_stats_count(struct net_device * netdev)836325945edSJakub Kicinski static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev)
837325945edSJakub Kicinski {
838325945edSJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
839325945edSJakub Kicinski 
84051a5e563SJakub Kicinski 	return NN_RVEC_GATHER_STATS + nn->max_r_vecs * NN_RVEC_PER_Q_STATS +
84151a5e563SJakub Kicinski 		NN_CTRL_PATH_STATS;
842325945edSJakub Kicinski }
843325945edSJakub Kicinski 
nfp_vnic_get_sw_stats_strings(struct net_device * netdev,u8 * data)844325945edSJakub Kicinski static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
8454c352362SJakub Kicinski {
8464c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
8474c352362SJakub Kicinski 	int i;
8484c352362SJakub Kicinski 
849f055a9dfSJakub Kicinski 	for (i = 0; i < nn->max_r_vecs; i++) {
8506a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rvec_%u_rx_pkts", i);
8516a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rvec_%u_tx_pkts", i);
8526a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rvec_%u_tx_busy", i);
8534c352362SJakub Kicinski 	}
854634287baSJakub Kicinski 
8556a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_rx_csum_ok");
8566a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_rx_csum_inner_ok");
8576a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_rx_csum_complete");
8586a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_rx_csum_err");
8596a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "rx_replace_buf_alloc_fail");
8606a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "rx_tls_decrypted_packets");
8616a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_tx_csum");
8626a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_tx_inner_csum");
8636a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "tx_gather");
8646a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "tx_lso");
8656a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "tx_tls_encrypted_packets");
8666a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "tx_tls_ooo");
8676a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "tx_tls_drop_no_sync_data");
86851a5e563SJakub Kicinski 
8696a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "hw_tls_no_space");
8706a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "rx_tls_resync_req_ok");
8716a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "rx_tls_resync_req_ign");
8726a143a7cSAlexander Duyck 	ethtool_sprintf(&data, "rx_tls_resync_sent");
873634287baSJakub Kicinski 
874325945edSJakub Kicinski 	return data;
8754c352362SJakub Kicinski }
876634287baSJakub Kicinski 
nfp_vnic_get_sw_stats(struct net_device * netdev,u64 * data)877325945edSJakub Kicinski static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
8784c352362SJakub Kicinski {
87918f76191SJakub Kicinski 	u64 gathered_stats[NN_RVEC_GATHER_STATS] = {};
8804c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
88118f76191SJakub Kicinski 	u64 tmp[NN_RVEC_GATHER_STATS];
882325945edSJakub Kicinski 	unsigned int i, j;
8834c352362SJakub Kicinski 
884f055a9dfSJakub Kicinski 	for (i = 0; i < nn->max_r_vecs; i++) {
8854c352362SJakub Kicinski 		unsigned int start;
8864c352362SJakub Kicinski 
8874c352362SJakub Kicinski 		do {
888068c38adSThomas Gleixner 			start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync);
889c3d64ad4SJakub Kicinski 			data[0] = nn->r_vecs[i].rx_pkts;
890325945edSJakub Kicinski 			tmp[0] = nn->r_vecs[i].hw_csum_rx_ok;
891325945edSJakub Kicinski 			tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok;
8920df57e60SJakub Kicinski 			tmp[2] = nn->r_vecs[i].hw_csum_rx_complete;
8930df57e60SJakub Kicinski 			tmp[3] = nn->r_vecs[i].hw_csum_rx_error;
8940df57e60SJakub Kicinski 			tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail;
8955bcb5c7eSDirk van der Merwe 			tmp[5] = nn->r_vecs[i].hw_tls_rx;
896068c38adSThomas Gleixner 		} while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start));
8974c352362SJakub Kicinski 
8984c352362SJakub Kicinski 		do {
899068c38adSThomas Gleixner 			start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync);
900c3d64ad4SJakub Kicinski 			data[1] = nn->r_vecs[i].tx_pkts;
901c3d64ad4SJakub Kicinski 			data[2] = nn->r_vecs[i].tx_busy;
9025bcb5c7eSDirk van der Merwe 			tmp[6] = nn->r_vecs[i].hw_csum_tx;
9035bcb5c7eSDirk van der Merwe 			tmp[7] = nn->r_vecs[i].hw_csum_tx_inner;
9045bcb5c7eSDirk van der Merwe 			tmp[8] = nn->r_vecs[i].tx_gather;
9055bcb5c7eSDirk van der Merwe 			tmp[9] = nn->r_vecs[i].tx_lso;
9065bcb5c7eSDirk van der Merwe 			tmp[10] = nn->r_vecs[i].hw_tls_tx;
9075bcb5c7eSDirk van der Merwe 			tmp[11] = nn->r_vecs[i].tls_tx_fallback;
9085bcb5c7eSDirk van der Merwe 			tmp[12] = nn->r_vecs[i].tls_tx_no_fallback;
909068c38adSThomas Gleixner 		} while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start));
9104c352362SJakub Kicinski 
91118f76191SJakub Kicinski 		data += NN_RVEC_PER_Q_STATS;
912c3d64ad4SJakub Kicinski 
91318f76191SJakub Kicinski 		for (j = 0; j < NN_RVEC_GATHER_STATS; j++)
914325945edSJakub Kicinski 			gathered_stats[j] += tmp[j];
9154c352362SJakub Kicinski 	}
916325945edSJakub Kicinski 
91718f76191SJakub Kicinski 	for (j = 0; j < NN_RVEC_GATHER_STATS; j++)
918325945edSJakub Kicinski 		*data++ = gathered_stats[j];
919325945edSJakub Kicinski 
92051a5e563SJakub Kicinski 	*data++ = atomic_read(&nn->ktls_no_space);
9216a35ddc5SJakub Kicinski 	*data++ = atomic_read(&nn->ktls_rx_resync_req);
9226a35ddc5SJakub Kicinski 	*data++ = atomic_read(&nn->ktls_rx_resync_ign);
9236a35ddc5SJakub Kicinski 	*data++ = atomic_read(&nn->ktls_rx_resync_sent);
92451a5e563SJakub Kicinski 
925325945edSJakub Kicinski 	return data;
9264c352362SJakub Kicinski }
927325945edSJakub Kicinski 
nfp_vnic_get_hw_stats_count(unsigned int num_vecs)928f055a9dfSJakub Kicinski static unsigned int nfp_vnic_get_hw_stats_count(unsigned int num_vecs)
929325945edSJakub Kicinski {
930f055a9dfSJakub Kicinski 	return NN_ET_GLOBAL_STATS_LEN + num_vecs * 4;
931325945edSJakub Kicinski }
932325945edSJakub Kicinski 
933325945edSJakub Kicinski static u8 *
nfp_vnic_get_hw_stats_strings(u8 * data,unsigned int num_vecs,bool repr)934f055a9dfSJakub Kicinski nfp_vnic_get_hw_stats_strings(u8 *data, unsigned int num_vecs, bool repr)
935325945edSJakub Kicinski {
936899a37adSJakub Kicinski 	int swap_off, i;
937325945edSJakub Kicinski 
938899a37adSJakub Kicinski 	BUILD_BUG_ON(NN_ET_GLOBAL_STATS_LEN < NN_ET_SWITCH_STATS_LEN * 2);
939899a37adSJakub Kicinski 	/* If repr is true first add SWITCH_STATS_LEN and then subtract it
940899a37adSJakub Kicinski 	 * effectively swapping the RX and TX statistics (giving us the RX
941899a37adSJakub Kicinski 	 * and TX from perspective of the switch).
942899a37adSJakub Kicinski 	 */
943899a37adSJakub Kicinski 	swap_off = repr * NN_ET_SWITCH_STATS_LEN;
944899a37adSJakub Kicinski 
945899a37adSJakub Kicinski 	for (i = 0; i < NN_ET_SWITCH_STATS_LEN; i++)
9466a143a7cSAlexander Duyck 		ethtool_sprintf(&data, nfp_net_et_stats[i + swap_off].name);
947899a37adSJakub Kicinski 
948899a37adSJakub Kicinski 	for (i = NN_ET_SWITCH_STATS_LEN; i < NN_ET_SWITCH_STATS_LEN * 2; i++)
9496a143a7cSAlexander Duyck 		ethtool_sprintf(&data, nfp_net_et_stats[i - swap_off].name);
950899a37adSJakub Kicinski 
951899a37adSJakub Kicinski 	for (i = NN_ET_SWITCH_STATS_LEN * 2; i < NN_ET_GLOBAL_STATS_LEN; i++)
9526a143a7cSAlexander Duyck 		ethtool_sprintf(&data, nfp_net_et_stats[i].name);
953325945edSJakub Kicinski 
954f055a9dfSJakub Kicinski 	for (i = 0; i < num_vecs; i++) {
9556a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rxq_%u_pkts", i);
9566a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rxq_%u_bytes", i);
9576a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "txq_%u_pkts", i);
9586a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "txq_%u_bytes", i);
959325945edSJakub Kicinski 	}
960325945edSJakub Kicinski 
961325945edSJakub Kicinski 	return data;
962325945edSJakub Kicinski }
963325945edSJakub Kicinski 
964325945edSJakub Kicinski static u64 *
nfp_vnic_get_hw_stats(u64 * data,u8 __iomem * mem,unsigned int num_vecs)965f055a9dfSJakub Kicinski nfp_vnic_get_hw_stats(u64 *data, u8 __iomem *mem, unsigned int num_vecs)
966325945edSJakub Kicinski {
967325945edSJakub Kicinski 	unsigned int i;
968325945edSJakub Kicinski 
969325945edSJakub Kicinski 	for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++)
970325945edSJakub Kicinski 		*data++ = readq(mem + nfp_net_et_stats[i].off);
971325945edSJakub Kicinski 
972f055a9dfSJakub Kicinski 	for (i = 0; i < num_vecs; i++) {
973325945edSJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i));
974325945edSJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i) + 8);
975f055a9dfSJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i));
976f055a9dfSJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i) + 8);
977325945edSJakub Kicinski 	}
978325945edSJakub Kicinski 
979325945edSJakub Kicinski 	return data;
980325945edSJakub Kicinski }
981325945edSJakub Kicinski 
nfp_vnic_get_tlv_stats_count(struct nfp_net * nn)982ca866ee8SJakub Kicinski static unsigned int nfp_vnic_get_tlv_stats_count(struct nfp_net *nn)
983ca866ee8SJakub Kicinski {
984ca866ee8SJakub Kicinski 	return nn->tlv_caps.vnic_stats_cnt + nn->max_r_vecs * 4;
985ca866ee8SJakub Kicinski }
986ca866ee8SJakub Kicinski 
nfp_vnic_get_tlv_stats_strings(struct nfp_net * nn,u8 * data)987ca866ee8SJakub Kicinski static u8 *nfp_vnic_get_tlv_stats_strings(struct nfp_net *nn, u8 *data)
988ca866ee8SJakub Kicinski {
989ca866ee8SJakub Kicinski 	unsigned int i, id;
990ca866ee8SJakub Kicinski 	u8 __iomem *mem;
991ca866ee8SJakub Kicinski 	u64 id_word = 0;
992ca866ee8SJakub Kicinski 
993ca866ee8SJakub Kicinski 	mem = nn->dp.ctrl_bar + nn->tlv_caps.vnic_stats_off;
994ca866ee8SJakub Kicinski 	for (i = 0; i < nn->tlv_caps.vnic_stats_cnt; i++) {
995ca866ee8SJakub Kicinski 		if (!(i % 4))
996ca866ee8SJakub Kicinski 			id_word = readq(mem + i * 2);
997ca866ee8SJakub Kicinski 
998ca866ee8SJakub Kicinski 		id = (u16)id_word;
999ca866ee8SJakub Kicinski 		id_word >>= 16;
1000ca866ee8SJakub Kicinski 
1001ca866ee8SJakub Kicinski 		if (id < ARRAY_SIZE(nfp_tlv_stat_names) &&
1002ca866ee8SJakub Kicinski 		    nfp_tlv_stat_names[id][0]) {
1003ca866ee8SJakub Kicinski 			memcpy(data, nfp_tlv_stat_names[id], ETH_GSTRING_LEN);
1004ca866ee8SJakub Kicinski 			data += ETH_GSTRING_LEN;
1005ca866ee8SJakub Kicinski 		} else {
10066a143a7cSAlexander Duyck 			ethtool_sprintf(&data, "dev_unknown_stat%u", id);
1007ca866ee8SJakub Kicinski 		}
1008ca866ee8SJakub Kicinski 	}
1009ca866ee8SJakub Kicinski 
1010ca866ee8SJakub Kicinski 	for (i = 0; i < nn->max_r_vecs; i++) {
10116a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rxq_%u_pkts", i);
10126a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "rxq_%u_bytes", i);
10136a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "txq_%u_pkts", i);
10146a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "txq_%u_bytes", i);
1015ca866ee8SJakub Kicinski 	}
1016ca866ee8SJakub Kicinski 
1017ca866ee8SJakub Kicinski 	return data;
1018ca866ee8SJakub Kicinski }
1019ca866ee8SJakub Kicinski 
nfp_vnic_get_tlv_stats(struct nfp_net * nn,u64 * data)1020ca866ee8SJakub Kicinski static u64 *nfp_vnic_get_tlv_stats(struct nfp_net *nn, u64 *data)
1021ca866ee8SJakub Kicinski {
1022ca866ee8SJakub Kicinski 	u8 __iomem *mem;
1023ca866ee8SJakub Kicinski 	unsigned int i;
1024ca866ee8SJakub Kicinski 
1025ca866ee8SJakub Kicinski 	mem = nn->dp.ctrl_bar + nn->tlv_caps.vnic_stats_off;
1026ca866ee8SJakub Kicinski 	mem += roundup(2 * nn->tlv_caps.vnic_stats_cnt, 8);
1027ca866ee8SJakub Kicinski 	for (i = 0; i < nn->tlv_caps.vnic_stats_cnt; i++)
1028ca866ee8SJakub Kicinski 		*data++ = readq(mem + i * 8);
1029ca866ee8SJakub Kicinski 
1030ca866ee8SJakub Kicinski 	mem = nn->dp.ctrl_bar;
1031ca866ee8SJakub Kicinski 	for (i = 0; i < nn->max_r_vecs; i++) {
1032ca866ee8SJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i));
1033ca866ee8SJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i) + 8);
1034ca866ee8SJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i));
1035ca866ee8SJakub Kicinski 		*data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i) + 8);
1036ca866ee8SJakub Kicinski 	}
1037ca866ee8SJakub Kicinski 
1038ca866ee8SJakub Kicinski 	return data;
1039ca866ee8SJakub Kicinski }
1040ca866ee8SJakub Kicinski 
nfp_mac_get_stats_count(struct net_device * netdev)1041098ce840SJakub Kicinski static unsigned int nfp_mac_get_stats_count(struct net_device *netdev)
1042098ce840SJakub Kicinski {
1043098ce840SJakub Kicinski 	struct nfp_port *port;
1044098ce840SJakub Kicinski 
1045098ce840SJakub Kicinski 	port = nfp_port_from_netdev(netdev);
1046098ce840SJakub Kicinski 	if (!__nfp_port_get_eth_port(port) || !port->eth_stats)
1047098ce840SJakub Kicinski 		return 0;
1048098ce840SJakub Kicinski 
1049098ce840SJakub Kicinski 	return ARRAY_SIZE(nfp_mac_et_stats);
1050098ce840SJakub Kicinski }
1051098ce840SJakub Kicinski 
nfp_mac_get_stats_strings(struct net_device * netdev,u8 * data)1052098ce840SJakub Kicinski static u8 *nfp_mac_get_stats_strings(struct net_device *netdev, u8 *data)
1053098ce840SJakub Kicinski {
1054098ce840SJakub Kicinski 	struct nfp_port *port;
1055098ce840SJakub Kicinski 	unsigned int i;
1056098ce840SJakub Kicinski 
1057098ce840SJakub Kicinski 	port = nfp_port_from_netdev(netdev);
1058098ce840SJakub Kicinski 	if (!__nfp_port_get_eth_port(port) || !port->eth_stats)
1059098ce840SJakub Kicinski 		return data;
1060098ce840SJakub Kicinski 
1061098ce840SJakub Kicinski 	for (i = 0; i < ARRAY_SIZE(nfp_mac_et_stats); i++)
10626a143a7cSAlexander Duyck 		ethtool_sprintf(&data, "mac.%s", nfp_mac_et_stats[i].name);
1063098ce840SJakub Kicinski 
1064098ce840SJakub Kicinski 	return data;
1065098ce840SJakub Kicinski }
1066098ce840SJakub Kicinski 
nfp_mac_get_stats(struct net_device * netdev,u64 * data)1067098ce840SJakub Kicinski static u64 *nfp_mac_get_stats(struct net_device *netdev, u64 *data)
1068098ce840SJakub Kicinski {
1069098ce840SJakub Kicinski 	struct nfp_port *port;
1070098ce840SJakub Kicinski 	unsigned int i;
1071098ce840SJakub Kicinski 
1072098ce840SJakub Kicinski 	port = nfp_port_from_netdev(netdev);
1073098ce840SJakub Kicinski 	if (!__nfp_port_get_eth_port(port) || !port->eth_stats)
1074098ce840SJakub Kicinski 		return data;
1075098ce840SJakub Kicinski 
1076098ce840SJakub Kicinski 	for (i = 0; i < ARRAY_SIZE(nfp_mac_et_stats); i++)
1077098ce840SJakub Kicinski 		*data++ = readq(port->eth_stats + nfp_mac_et_stats[i].off);
1078098ce840SJakub Kicinski 
1079098ce840SJakub Kicinski 	return data;
1080098ce840SJakub Kicinski }
1081098ce840SJakub Kicinski 
nfp_net_get_strings(struct net_device * netdev,u32 stringset,u8 * data)1082325945edSJakub Kicinski static void nfp_net_get_strings(struct net_device *netdev,
1083325945edSJakub Kicinski 				u32 stringset, u8 *data)
1084325945edSJakub Kicinski {
1085325945edSJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
1086325945edSJakub Kicinski 
1087325945edSJakub Kicinski 	switch (stringset) {
1088325945edSJakub Kicinski 	case ETH_SS_STATS:
1089325945edSJakub Kicinski 		data = nfp_vnic_get_sw_stats_strings(netdev, data);
1090ca866ee8SJakub Kicinski 		if (!nn->tlv_caps.vnic_stats_off)
1091ca866ee8SJakub Kicinski 			data = nfp_vnic_get_hw_stats_strings(data,
1092ca866ee8SJakub Kicinski 							     nn->max_r_vecs,
1093899a37adSJakub Kicinski 							     false);
1094ca866ee8SJakub Kicinski 		else
1095ca866ee8SJakub Kicinski 			data = nfp_vnic_get_tlv_stats_strings(nn, data);
1096098ce840SJakub Kicinski 		data = nfp_mac_get_stats_strings(netdev, data);
109721f31bc0SJakub Kicinski 		data = nfp_app_port_get_stats_strings(nn->port, data);
1098325945edSJakub Kicinski 		break;
109915137daeSFei Qin 	case ETH_SS_TEST:
110015137daeSFei Qin 		nfp_get_self_test_strings(netdev, data);
110115137daeSFei Qin 		break;
1102325945edSJakub Kicinski 	}
1103325945edSJakub Kicinski }
1104325945edSJakub Kicinski 
1105325945edSJakub Kicinski static void
nfp_net_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)1106325945edSJakub Kicinski nfp_net_get_stats(struct net_device *netdev, struct ethtool_stats *stats,
1107325945edSJakub Kicinski 		  u64 *data)
1108325945edSJakub Kicinski {
1109325945edSJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
1110325945edSJakub Kicinski 
1111325945edSJakub Kicinski 	data = nfp_vnic_get_sw_stats(netdev, data);
1112ca866ee8SJakub Kicinski 	if (!nn->tlv_caps.vnic_stats_off)
1113ca866ee8SJakub Kicinski 		data = nfp_vnic_get_hw_stats(data, nn->dp.ctrl_bar,
1114ca866ee8SJakub Kicinski 					     nn->max_r_vecs);
1115ca866ee8SJakub Kicinski 	else
1116ca866ee8SJakub Kicinski 		data = nfp_vnic_get_tlv_stats(nn, data);
1117098ce840SJakub Kicinski 	data = nfp_mac_get_stats(netdev, data);
111821f31bc0SJakub Kicinski 	data = nfp_app_port_get_stats(nn->port, data);
11194c352362SJakub Kicinski }
11204c352362SJakub Kicinski 
nfp_net_get_sset_count(struct net_device * netdev,int sset)11214c352362SJakub Kicinski static int nfp_net_get_sset_count(struct net_device *netdev, int sset)
11224c352362SJakub Kicinski {
11234c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
1124ca866ee8SJakub Kicinski 	unsigned int cnt;
11254c352362SJakub Kicinski 
11264c352362SJakub Kicinski 	switch (sset) {
11274c352362SJakub Kicinski 	case ETH_SS_STATS:
1128ca866ee8SJakub Kicinski 		cnt = nfp_vnic_get_sw_stats_count(netdev);
1129ca866ee8SJakub Kicinski 		if (!nn->tlv_caps.vnic_stats_off)
1130ca866ee8SJakub Kicinski 			cnt += nfp_vnic_get_hw_stats_count(nn->max_r_vecs);
1131ca866ee8SJakub Kicinski 		else
1132ca866ee8SJakub Kicinski 			cnt += nfp_vnic_get_tlv_stats_count(nn);
1133ca866ee8SJakub Kicinski 		cnt += nfp_mac_get_stats_count(netdev);
1134ca866ee8SJakub Kicinski 		cnt += nfp_app_port_get_stats_count(nn->port);
1135ca866ee8SJakub Kicinski 		return cnt;
113615137daeSFei Qin 	case ETH_SS_TEST:
113715137daeSFei Qin 		return nfp_get_self_test_count(netdev);
11384c352362SJakub Kicinski 	default:
11394c352362SJakub Kicinski 		return -EOPNOTSUPP;
11404c352362SJakub Kicinski 	}
11414c352362SJakub Kicinski }
11424c352362SJakub Kicinski 
nfp_port_get_strings(struct net_device * netdev,u32 stringset,u8 * data)1143899a37adSJakub Kicinski static void nfp_port_get_strings(struct net_device *netdev,
1144899a37adSJakub Kicinski 				 u32 stringset, u8 *data)
1145899a37adSJakub Kicinski {
1146899a37adSJakub Kicinski 	struct nfp_port *port = nfp_port_from_netdev(netdev);
1147899a37adSJakub Kicinski 
1148899a37adSJakub Kicinski 	switch (stringset) {
1149899a37adSJakub Kicinski 	case ETH_SS_STATS:
1150899a37adSJakub Kicinski 		if (nfp_port_is_vnic(port))
1151f055a9dfSJakub Kicinski 			data = nfp_vnic_get_hw_stats_strings(data, 0, true);
1152899a37adSJakub Kicinski 		else
1153899a37adSJakub Kicinski 			data = nfp_mac_get_stats_strings(netdev, data);
115421f31bc0SJakub Kicinski 		data = nfp_app_port_get_stats_strings(port, data);
1155899a37adSJakub Kicinski 		break;
115615137daeSFei Qin 	case ETH_SS_TEST:
115715137daeSFei Qin 		nfp_get_self_test_strings(netdev, data);
115815137daeSFei Qin 		break;
1159899a37adSJakub Kicinski 	}
1160899a37adSJakub Kicinski }
1161899a37adSJakub Kicinski 
1162899a37adSJakub Kicinski static void
nfp_port_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)1163899a37adSJakub Kicinski nfp_port_get_stats(struct net_device *netdev, struct ethtool_stats *stats,
1164899a37adSJakub Kicinski 		   u64 *data)
1165899a37adSJakub Kicinski {
1166899a37adSJakub Kicinski 	struct nfp_port *port = nfp_port_from_netdev(netdev);
1167899a37adSJakub Kicinski 
1168899a37adSJakub Kicinski 	if (nfp_port_is_vnic(port))
1169f055a9dfSJakub Kicinski 		data = nfp_vnic_get_hw_stats(data, port->vnic, 0);
1170899a37adSJakub Kicinski 	else
1171899a37adSJakub Kicinski 		data = nfp_mac_get_stats(netdev, data);
117221f31bc0SJakub Kicinski 	data = nfp_app_port_get_stats(port, data);
1173899a37adSJakub Kicinski }
1174899a37adSJakub Kicinski 
nfp_port_get_sset_count(struct net_device * netdev,int sset)1175899a37adSJakub Kicinski static int nfp_port_get_sset_count(struct net_device *netdev, int sset)
1176899a37adSJakub Kicinski {
1177899a37adSJakub Kicinski 	struct nfp_port *port = nfp_port_from_netdev(netdev);
1178899a37adSJakub Kicinski 	unsigned int count;
1179899a37adSJakub Kicinski 
1180899a37adSJakub Kicinski 	switch (sset) {
1181899a37adSJakub Kicinski 	case ETH_SS_STATS:
1182899a37adSJakub Kicinski 		if (nfp_port_is_vnic(port))
1183f055a9dfSJakub Kicinski 			count = nfp_vnic_get_hw_stats_count(0);
1184899a37adSJakub Kicinski 		else
1185899a37adSJakub Kicinski 			count = nfp_mac_get_stats_count(netdev);
118621f31bc0SJakub Kicinski 		count += nfp_app_port_get_stats_count(port);
1187899a37adSJakub Kicinski 		return count;
118815137daeSFei Qin 	case ETH_SS_TEST:
118915137daeSFei Qin 		return nfp_get_self_test_count(netdev);
1190899a37adSJakub Kicinski 	default:
1191899a37adSJakub Kicinski 		return -EOPNOTSUPP;
1192899a37adSJakub Kicinski 	}
1193899a37adSJakub Kicinski }
1194899a37adSJakub Kicinski 
nfp_port_fec_ethtool_to_nsp(u32 fec)11950d087093SDirk van der Merwe static int nfp_port_fec_ethtool_to_nsp(u32 fec)
11960d087093SDirk van der Merwe {
11970d087093SDirk van der Merwe 	switch (fec) {
11980d087093SDirk van der Merwe 	case ETHTOOL_FEC_AUTO:
11990d087093SDirk van der Merwe 		return NFP_FEC_AUTO_BIT;
12000d087093SDirk van der Merwe 	case ETHTOOL_FEC_OFF:
12010d087093SDirk van der Merwe 		return NFP_FEC_DISABLED_BIT;
12020d087093SDirk van der Merwe 	case ETHTOOL_FEC_RS:
12030d087093SDirk van der Merwe 		return NFP_FEC_REED_SOLOMON_BIT;
12040d087093SDirk van der Merwe 	case ETHTOOL_FEC_BASER:
12050d087093SDirk van der Merwe 		return NFP_FEC_BASER_BIT;
12060d087093SDirk van der Merwe 	default:
12070d087093SDirk van der Merwe 		/* NSP only supports a single mode at a time */
12080d087093SDirk van der Merwe 		return -EOPNOTSUPP;
12090d087093SDirk van der Merwe 	}
12100d087093SDirk van der Merwe }
12110d087093SDirk van der Merwe 
nfp_port_fec_nsp_to_ethtool(u32 fec)12120d087093SDirk van der Merwe static u32 nfp_port_fec_nsp_to_ethtool(u32 fec)
12130d087093SDirk van der Merwe {
12140d087093SDirk van der Merwe 	u32 result = 0;
12150d087093SDirk van der Merwe 
12160d087093SDirk van der Merwe 	if (fec & NFP_FEC_AUTO)
12170d087093SDirk van der Merwe 		result |= ETHTOOL_FEC_AUTO;
12180d087093SDirk van der Merwe 	if (fec & NFP_FEC_BASER)
12190d087093SDirk van der Merwe 		result |= ETHTOOL_FEC_BASER;
12200d087093SDirk van der Merwe 	if (fec & NFP_FEC_REED_SOLOMON)
12210d087093SDirk van der Merwe 		result |= ETHTOOL_FEC_RS;
12220d087093SDirk van der Merwe 	if (fec & NFP_FEC_DISABLED)
12230d087093SDirk van der Merwe 		result |= ETHTOOL_FEC_OFF;
12240d087093SDirk van der Merwe 
12250d087093SDirk van der Merwe 	return result ?: ETHTOOL_FEC_NONE;
12260d087093SDirk van der Merwe }
12270d087093SDirk van der Merwe 
12280d087093SDirk van der Merwe static int
nfp_port_get_fecparam(struct net_device * netdev,struct ethtool_fecparam * param)12290d087093SDirk van der Merwe nfp_port_get_fecparam(struct net_device *netdev,
12300d087093SDirk van der Merwe 		      struct ethtool_fecparam *param)
12310d087093SDirk van der Merwe {
12320d087093SDirk van der Merwe 	struct nfp_eth_table_port *eth_port;
12330d087093SDirk van der Merwe 	struct nfp_port *port;
12340d087093SDirk van der Merwe 
12355f6857e8SJakub Kicinski 	param->active_fec = ETHTOOL_FEC_NONE;
12365f6857e8SJakub Kicinski 	param->fec = ETHTOOL_FEC_NONE;
12370d087093SDirk van der Merwe 
12380d087093SDirk van der Merwe 	port = nfp_port_from_netdev(netdev);
12390d087093SDirk van der Merwe 	eth_port = nfp_port_get_eth_port(port);
12400d087093SDirk van der Merwe 	if (!eth_port)
12410d087093SDirk van der Merwe 		return -EOPNOTSUPP;
12420d087093SDirk van der Merwe 
12430d087093SDirk van der Merwe 	if (!nfp_eth_can_support_fec(eth_port))
12440d087093SDirk van der Merwe 		return 0;
12450d087093SDirk van der Merwe 
12460d087093SDirk van der Merwe 	param->fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec_modes_supported);
1247fc26e70fSYinjun Zhang 	param->active_fec = nfp_port_fec_nsp_to_ethtool(BIT(eth_port->act_fec));
12480d087093SDirk van der Merwe 
12490d087093SDirk van der Merwe 	return 0;
12500d087093SDirk van der Merwe }
12510d087093SDirk van der Merwe 
12520d087093SDirk van der Merwe static int
nfp_port_set_fecparam(struct net_device * netdev,struct ethtool_fecparam * param)12530d087093SDirk van der Merwe nfp_port_set_fecparam(struct net_device *netdev,
12540d087093SDirk van der Merwe 		      struct ethtool_fecparam *param)
12550d087093SDirk van der Merwe {
12560d087093SDirk van der Merwe 	struct nfp_eth_table_port *eth_port;
12570d087093SDirk van der Merwe 	struct nfp_port *port;
12580d087093SDirk van der Merwe 	int err, fec;
12590d087093SDirk van der Merwe 
12600d087093SDirk van der Merwe 	port = nfp_port_from_netdev(netdev);
12610d087093SDirk van der Merwe 	eth_port = nfp_port_get_eth_port(port);
12620d087093SDirk van der Merwe 	if (!eth_port)
12630d087093SDirk van der Merwe 		return -EOPNOTSUPP;
12640d087093SDirk van der Merwe 
12650d087093SDirk van der Merwe 	if (!nfp_eth_can_support_fec(eth_port))
12660d087093SDirk van der Merwe 		return -EOPNOTSUPP;
12670d087093SDirk van der Merwe 
12680d087093SDirk van der Merwe 	fec = nfp_port_fec_ethtool_to_nsp(param->fec);
12690d087093SDirk van der Merwe 	if (fec < 0)
12700d087093SDirk van der Merwe 		return fec;
12710d087093SDirk van der Merwe 
12720d087093SDirk van der Merwe 	err = nfp_eth_set_fec(port->app->cpp, eth_port->index, fec);
12730d087093SDirk van der Merwe 	if (!err)
12740d087093SDirk van der Merwe 		/* Only refresh if we did something */
12750d087093SDirk van der Merwe 		nfp_net_refresh_port_table(port);
12760d087093SDirk van der Merwe 
12770d087093SDirk van der Merwe 	return err < 0 ? err : 0;
12780d087093SDirk van der Merwe }
12790d087093SDirk van der Merwe 
12804c352362SJakub Kicinski /* RX network flow classification (RSS, filters, etc)
12814c352362SJakub Kicinski  */
ethtool_flow_to_nfp_flag(u32 flow_type)12824c352362SJakub Kicinski static u32 ethtool_flow_to_nfp_flag(u32 flow_type)
12834c352362SJakub Kicinski {
12844c352362SJakub Kicinski 	static const u32 xlate_ethtool_to_nfp[IPV6_FLOW + 1] = {
12854c352362SJakub Kicinski 		[TCP_V4_FLOW]	= NFP_NET_CFG_RSS_IPV4_TCP,
12864c352362SJakub Kicinski 		[TCP_V6_FLOW]	= NFP_NET_CFG_RSS_IPV6_TCP,
12874c352362SJakub Kicinski 		[UDP_V4_FLOW]	= NFP_NET_CFG_RSS_IPV4_UDP,
12884c352362SJakub Kicinski 		[UDP_V6_FLOW]	= NFP_NET_CFG_RSS_IPV6_UDP,
12894c352362SJakub Kicinski 		[IPV4_FLOW]	= NFP_NET_CFG_RSS_IPV4,
12904c352362SJakub Kicinski 		[IPV6_FLOW]	= NFP_NET_CFG_RSS_IPV6,
12914c352362SJakub Kicinski 	};
12924c352362SJakub Kicinski 
12934c352362SJakub Kicinski 	if (flow_type >= ARRAY_SIZE(xlate_ethtool_to_nfp))
12944c352362SJakub Kicinski 		return 0;
12954c352362SJakub Kicinski 
12964c352362SJakub Kicinski 	return xlate_ethtool_to_nfp[flow_type];
12974c352362SJakub Kicinski }
12984c352362SJakub Kicinski 
nfp_net_get_rss_hash_opts(struct nfp_net * nn,struct ethtool_rxnfc * cmd)12994c352362SJakub Kicinski static int nfp_net_get_rss_hash_opts(struct nfp_net *nn,
13004c352362SJakub Kicinski 				     struct ethtool_rxnfc *cmd)
13014c352362SJakub Kicinski {
13024c352362SJakub Kicinski 	u32 nfp_rss_flag;
13034c352362SJakub Kicinski 
13044c352362SJakub Kicinski 	cmd->data = 0;
13054c352362SJakub Kicinski 
1306611bdd49SEdwin Peer 	if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
13074c352362SJakub Kicinski 		return -EOPNOTSUPP;
13084c352362SJakub Kicinski 
13094c352362SJakub Kicinski 	nfp_rss_flag = ethtool_flow_to_nfp_flag(cmd->flow_type);
13104c352362SJakub Kicinski 	if (!nfp_rss_flag)
13114c352362SJakub Kicinski 		return -EINVAL;
13124c352362SJakub Kicinski 
13134c352362SJakub Kicinski 	cmd->data |= RXH_IP_SRC | RXH_IP_DST;
13144c352362SJakub Kicinski 	if (nn->rss_cfg & nfp_rss_flag)
13154c352362SJakub Kicinski 		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
13164c352362SJakub Kicinski 
13174c352362SJakub Kicinski 	return 0;
13184c352362SJakub Kicinski }
13194c352362SJakub Kicinski 
nfp_net_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * cmd,u32 * rule_locs)13204c352362SJakub Kicinski static int nfp_net_get_rxnfc(struct net_device *netdev,
13214c352362SJakub Kicinski 			     struct ethtool_rxnfc *cmd, u32 *rule_locs)
13224c352362SJakub Kicinski {
13234c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
13244c352362SJakub Kicinski 
13254c352362SJakub Kicinski 	switch (cmd->cmd) {
13264c352362SJakub Kicinski 	case ETHTOOL_GRXRINGS:
132779c12a75SJakub Kicinski 		cmd->data = nn->dp.num_rx_rings;
13284c352362SJakub Kicinski 		return 0;
13294c352362SJakub Kicinski 	case ETHTOOL_GRXFH:
13304c352362SJakub Kicinski 		return nfp_net_get_rss_hash_opts(nn, cmd);
13314c352362SJakub Kicinski 	default:
13324c352362SJakub Kicinski 		return -EOPNOTSUPP;
13334c352362SJakub Kicinski 	}
13344c352362SJakub Kicinski }
13354c352362SJakub Kicinski 
nfp_net_set_rss_hash_opt(struct nfp_net * nn,struct ethtool_rxnfc * nfc)13364c352362SJakub Kicinski static int nfp_net_set_rss_hash_opt(struct nfp_net *nn,
13374c352362SJakub Kicinski 				    struct ethtool_rxnfc *nfc)
13384c352362SJakub Kicinski {
13394c352362SJakub Kicinski 	u32 new_rss_cfg = nn->rss_cfg;
13404c352362SJakub Kicinski 	u32 nfp_rss_flag;
13414c352362SJakub Kicinski 	int err;
13424c352362SJakub Kicinski 
1343611bdd49SEdwin Peer 	if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
13444c352362SJakub Kicinski 		return -EOPNOTSUPP;
13454c352362SJakub Kicinski 
13464c352362SJakub Kicinski 	/* RSS only supports IP SA/DA and L4 src/dst ports  */
13474c352362SJakub Kicinski 	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
13484c352362SJakub Kicinski 			  RXH_L4_B_0_1 | RXH_L4_B_2_3))
13494c352362SJakub Kicinski 		return -EINVAL;
13504c352362SJakub Kicinski 
13514c352362SJakub Kicinski 	/* We need at least the IP SA/DA fields for hashing */
13524c352362SJakub Kicinski 	if (!(nfc->data & RXH_IP_SRC) ||
13534c352362SJakub Kicinski 	    !(nfc->data & RXH_IP_DST))
13544c352362SJakub Kicinski 		return -EINVAL;
13554c352362SJakub Kicinski 
13564c352362SJakub Kicinski 	nfp_rss_flag = ethtool_flow_to_nfp_flag(nfc->flow_type);
13574c352362SJakub Kicinski 	if (!nfp_rss_flag)
13584c352362SJakub Kicinski 		return -EINVAL;
13594c352362SJakub Kicinski 
13604c352362SJakub Kicinski 	switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
13614c352362SJakub Kicinski 	case 0:
13624c352362SJakub Kicinski 		new_rss_cfg &= ~nfp_rss_flag;
13634c352362SJakub Kicinski 		break;
13644c352362SJakub Kicinski 	case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
13654c352362SJakub Kicinski 		new_rss_cfg |= nfp_rss_flag;
13664c352362SJakub Kicinski 		break;
13674c352362SJakub Kicinski 	default:
13684c352362SJakub Kicinski 		return -EINVAL;
13694c352362SJakub Kicinski 	}
13704c352362SJakub Kicinski 
13719ff304bfSJakub Kicinski 	new_rss_cfg |= FIELD_PREP(NFP_NET_CFG_RSS_HFUNC, nn->rss_hfunc);
13724c352362SJakub Kicinski 	new_rss_cfg |= NFP_NET_CFG_RSS_MASK;
13734c352362SJakub Kicinski 
13744c352362SJakub Kicinski 	if (new_rss_cfg == nn->rss_cfg)
13754c352362SJakub Kicinski 		return 0;
13764c352362SJakub Kicinski 
1377d2b84397SJakub Kicinski 	writel(new_rss_cfg, nn->dp.ctrl_bar + NFP_NET_CFG_RSS_CTRL);
13784c352362SJakub Kicinski 	err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_RSS);
13794c352362SJakub Kicinski 	if (err)
13804c352362SJakub Kicinski 		return err;
13814c352362SJakub Kicinski 
13824c352362SJakub Kicinski 	nn->rss_cfg = new_rss_cfg;
13834c352362SJakub Kicinski 
13844c352362SJakub Kicinski 	nn_dbg(nn, "Changed RSS config to 0x%x\n", nn->rss_cfg);
13854c352362SJakub Kicinski 	return 0;
13864c352362SJakub Kicinski }
13874c352362SJakub Kicinski 
nfp_net_set_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * cmd)13884c352362SJakub Kicinski static int nfp_net_set_rxnfc(struct net_device *netdev,
13894c352362SJakub Kicinski 			     struct ethtool_rxnfc *cmd)
13904c352362SJakub Kicinski {
13914c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
13924c352362SJakub Kicinski 
13934c352362SJakub Kicinski 	switch (cmd->cmd) {
13944c352362SJakub Kicinski 	case ETHTOOL_SRXFH:
13954c352362SJakub Kicinski 		return nfp_net_set_rss_hash_opt(nn, cmd);
13964c352362SJakub Kicinski 	default:
13974c352362SJakub Kicinski 		return -EOPNOTSUPP;
13984c352362SJakub Kicinski 	}
13994c352362SJakub Kicinski }
14004c352362SJakub Kicinski 
nfp_net_get_rxfh_indir_size(struct net_device * netdev)14014c352362SJakub Kicinski static u32 nfp_net_get_rxfh_indir_size(struct net_device *netdev)
14024c352362SJakub Kicinski {
14034c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
14044c352362SJakub Kicinski 
1405611bdd49SEdwin Peer 	if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
14064c352362SJakub Kicinski 		return 0;
14074c352362SJakub Kicinski 
14084c352362SJakub Kicinski 	return ARRAY_SIZE(nn->rss_itbl);
14094c352362SJakub Kicinski }
14104c352362SJakub Kicinski 
nfp_net_get_rxfh_key_size(struct net_device * netdev)14114c352362SJakub Kicinski static u32 nfp_net_get_rxfh_key_size(struct net_device *netdev)
14124c352362SJakub Kicinski {
14139ff304bfSJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
14149ff304bfSJakub Kicinski 
1415611bdd49SEdwin Peer 	if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
14169ff304bfSJakub Kicinski 		return -EOPNOTSUPP;
14179ff304bfSJakub Kicinski 
14189ff304bfSJakub Kicinski 	return nfp_net_rss_key_sz(nn);
14194c352362SJakub Kicinski }
14204c352362SJakub Kicinski 
nfp_net_get_rxfh(struct net_device * netdev,u32 * indir,u8 * key,u8 * hfunc)14214c352362SJakub Kicinski static int nfp_net_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
14224c352362SJakub Kicinski 			    u8 *hfunc)
14234c352362SJakub Kicinski {
14244c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
14254c352362SJakub Kicinski 	int i;
14264c352362SJakub Kicinski 
1427611bdd49SEdwin Peer 	if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
14284c352362SJakub Kicinski 		return -EOPNOTSUPP;
14294c352362SJakub Kicinski 
14304c352362SJakub Kicinski 	if (indir)
14314c352362SJakub Kicinski 		for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
14324c352362SJakub Kicinski 			indir[i] = nn->rss_itbl[i];
14334c352362SJakub Kicinski 	if (key)
14349ff304bfSJakub Kicinski 		memcpy(key, nn->rss_key, nfp_net_rss_key_sz(nn));
14359ff304bfSJakub Kicinski 	if (hfunc) {
14369ff304bfSJakub Kicinski 		*hfunc = nn->rss_hfunc;
14379ff304bfSJakub Kicinski 		if (*hfunc >= 1 << ETH_RSS_HASH_FUNCS_COUNT)
14389ff304bfSJakub Kicinski 			*hfunc = ETH_RSS_HASH_UNKNOWN;
14399ff304bfSJakub Kicinski 	}
14404c352362SJakub Kicinski 
14414c352362SJakub Kicinski 	return 0;
14424c352362SJakub Kicinski }
14434c352362SJakub Kicinski 
nfp_net_set_rxfh(struct net_device * netdev,const u32 * indir,const u8 * key,const u8 hfunc)14444c352362SJakub Kicinski static int nfp_net_set_rxfh(struct net_device *netdev,
14454c352362SJakub Kicinski 			    const u32 *indir, const u8 *key,
14464c352362SJakub Kicinski 			    const u8 hfunc)
14474c352362SJakub Kicinski {
14484c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
14494c352362SJakub Kicinski 	int i;
14504c352362SJakub Kicinski 
1451611bdd49SEdwin Peer 	if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) ||
14529ff304bfSJakub Kicinski 	    !(hfunc == ETH_RSS_HASH_NO_CHANGE || hfunc == nn->rss_hfunc))
14534c352362SJakub Kicinski 		return -EOPNOTSUPP;
14544c352362SJakub Kicinski 
14554c352362SJakub Kicinski 	if (!key && !indir)
14564c352362SJakub Kicinski 		return 0;
14574c352362SJakub Kicinski 
14584c352362SJakub Kicinski 	if (key) {
14599ff304bfSJakub Kicinski 		memcpy(nn->rss_key, key, nfp_net_rss_key_sz(nn));
14604c352362SJakub Kicinski 		nfp_net_rss_write_key(nn);
14614c352362SJakub Kicinski 	}
14624c352362SJakub Kicinski 	if (indir) {
14634c352362SJakub Kicinski 		for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
14644c352362SJakub Kicinski 			nn->rss_itbl[i] = indir[i];
14654c352362SJakub Kicinski 
14664c352362SJakub Kicinski 		nfp_net_rss_write_itbl(nn);
14674c352362SJakub Kicinski 	}
14684c352362SJakub Kicinski 
14694c352362SJakub Kicinski 	return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_RSS);
14704c352362SJakub Kicinski }
14714c352362SJakub Kicinski 
14724c352362SJakub Kicinski /* Dump BAR registers
14734c352362SJakub Kicinski  */
nfp_net_get_regs_len(struct net_device * netdev)14744c352362SJakub Kicinski static int nfp_net_get_regs_len(struct net_device *netdev)
14754c352362SJakub Kicinski {
14764c352362SJakub Kicinski 	return NFP_NET_CFG_BAR_SZ;
14774c352362SJakub Kicinski }
14784c352362SJakub Kicinski 
nfp_net_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)14794c352362SJakub Kicinski static void nfp_net_get_regs(struct net_device *netdev,
14804c352362SJakub Kicinski 			     struct ethtool_regs *regs, void *p)
14814c352362SJakub Kicinski {
14824c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
14834c352362SJakub Kicinski 	u32 *regs_buf = p;
14844c352362SJakub Kicinski 	int i;
14854c352362SJakub Kicinski 
14864c352362SJakub Kicinski 	regs->version = nn_readl(nn, NFP_NET_CFG_VERSION);
14874c352362SJakub Kicinski 
14884c352362SJakub Kicinski 	for (i = 0; i < NFP_NET_CFG_BAR_SZ / sizeof(u32); i++)
1489d2b84397SJakub Kicinski 		regs_buf[i] = readl(nn->dp.ctrl_bar + (i * sizeof(u32)));
14904c352362SJakub Kicinski }
14914c352362SJakub Kicinski 
nfp_net_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)14924c352362SJakub Kicinski static int nfp_net_get_coalesce(struct net_device *netdev,
1493f3ccfda1SYufeng Mo 				struct ethtool_coalesce *ec,
1494f3ccfda1SYufeng Mo 				struct kernel_ethtool_coalesce *kernel_coal,
1495f3ccfda1SYufeng Mo 				struct netlink_ext_ack *extack)
14964c352362SJakub Kicinski {
14974c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
14984c352362SJakub Kicinski 
14994c352362SJakub Kicinski 	if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
15004c352362SJakub Kicinski 		return -EINVAL;
15014c352362SJakub Kicinski 
15029d32e4e7SYinjun Zhang 	ec->use_adaptive_rx_coalesce = nn->rx_coalesce_adapt_on;
15039d32e4e7SYinjun Zhang 	ec->use_adaptive_tx_coalesce = nn->tx_coalesce_adapt_on;
15049d32e4e7SYinjun Zhang 
15054c352362SJakub Kicinski 	ec->rx_coalesce_usecs       = nn->rx_coalesce_usecs;
15064c352362SJakub Kicinski 	ec->rx_max_coalesced_frames = nn->rx_coalesce_max_frames;
15074c352362SJakub Kicinski 	ec->tx_coalesce_usecs       = nn->tx_coalesce_usecs;
15084c352362SJakub Kicinski 	ec->tx_max_coalesced_frames = nn->tx_coalesce_max_frames;
15094c352362SJakub Kicinski 
15104c352362SJakub Kicinski 	return 0;
15114c352362SJakub Kicinski }
15124c352362SJakub Kicinski 
1513af623682SJakub Kicinski /* Other debug dumps
1514af623682SJakub Kicinski  */
1515af623682SJakub Kicinski static int
nfp_dump_nsp_diag(struct nfp_app * app,struct ethtool_dump * dump,void * buffer)1516a2f4c3d9SJakub Kicinski nfp_dump_nsp_diag(struct nfp_app *app, struct ethtool_dump *dump, void *buffer)
1517af623682SJakub Kicinski {
1518af623682SJakub Kicinski 	struct nfp_resource *res;
1519af623682SJakub Kicinski 	int ret;
1520af623682SJakub Kicinski 
1521a2f4c3d9SJakub Kicinski 	if (!app)
1522af623682SJakub Kicinski 		return -EOPNOTSUPP;
1523af623682SJakub Kicinski 
1524af623682SJakub Kicinski 	dump->version = 1;
1525af623682SJakub Kicinski 	dump->flag = NFP_DUMP_NSP_DIAG;
1526af623682SJakub Kicinski 
1527a2f4c3d9SJakub Kicinski 	res = nfp_resource_acquire(app->cpp, NFP_RESOURCE_NSP_DIAG);
1528af623682SJakub Kicinski 	if (IS_ERR(res))
1529af623682SJakub Kicinski 		return PTR_ERR(res);
1530af623682SJakub Kicinski 
1531af623682SJakub Kicinski 	if (buffer) {
1532af623682SJakub Kicinski 		if (dump->len != nfp_resource_size(res)) {
1533af623682SJakub Kicinski 			ret = -EINVAL;
1534af623682SJakub Kicinski 			goto exit_release;
1535af623682SJakub Kicinski 		}
1536af623682SJakub Kicinski 
1537a2f4c3d9SJakub Kicinski 		ret = nfp_cpp_read(app->cpp, nfp_resource_cpp_id(res),
1538af623682SJakub Kicinski 				   nfp_resource_address(res),
1539af623682SJakub Kicinski 				   buffer, dump->len);
1540af623682SJakub Kicinski 		if (ret != dump->len)
1541af623682SJakub Kicinski 			ret = ret < 0 ? ret : -EIO;
1542af623682SJakub Kicinski 		else
1543af623682SJakub Kicinski 			ret = 0;
1544af623682SJakub Kicinski 	} else {
1545af623682SJakub Kicinski 		dump->len = nfp_resource_size(res);
1546af623682SJakub Kicinski 		ret = 0;
1547af623682SJakub Kicinski 	}
1548af623682SJakub Kicinski exit_release:
1549af623682SJakub Kicinski 	nfp_resource_release(res);
1550af623682SJakub Kicinski 
1551af623682SJakub Kicinski 	return ret;
1552af623682SJakub Kicinski }
1553af623682SJakub Kicinski 
1554d79e19f5SCarl Heymann /* Set the dump flag/level. Calculate the dump length for flag > 0 only (new TLV
1555d79e19f5SCarl Heymann  * based dumps), since flag 0 (default) calculates the length in
1556d79e19f5SCarl Heymann  * nfp_app_get_dump_flag(), and we need to support triggering a level 0 dump
1557d79e19f5SCarl Heymann  * without setting the flag first, for backward compatibility.
1558d79e19f5SCarl Heymann  */
nfp_app_set_dump(struct net_device * netdev,struct ethtool_dump * val)1559a2f4c3d9SJakub Kicinski static int nfp_app_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1560af623682SJakub Kicinski {
1561a2f4c3d9SJakub Kicinski 	struct nfp_app *app = nfp_app_from_netdev(netdev);
1562d79e19f5SCarl Heymann 	s64 len;
1563af623682SJakub Kicinski 
1564a2f4c3d9SJakub Kicinski 	if (!app)
1565af623682SJakub Kicinski 		return -EOPNOTSUPP;
1566af623682SJakub Kicinski 
1567d79e19f5SCarl Heymann 	if (val->flag == NFP_DUMP_NSP_DIAG) {
1568d79e19f5SCarl Heymann 		app->pf->dump_flag = val->flag;
1569d79e19f5SCarl Heymann 		return 0;
1570d79e19f5SCarl Heymann 	}
1571d79e19f5SCarl Heymann 
1572d79e19f5SCarl Heymann 	if (!app->pf->dumpspec)
1573d79e19f5SCarl Heymann 		return -EOPNOTSUPP;
1574d79e19f5SCarl Heymann 
1575d79e19f5SCarl Heymann 	len = nfp_net_dump_calculate_size(app->pf, app->pf->dumpspec,
1576d79e19f5SCarl Heymann 					  val->flag);
1577d79e19f5SCarl Heymann 	if (len < 0)
1578d79e19f5SCarl Heymann 		return len;
1579d79e19f5SCarl Heymann 
1580d79e19f5SCarl Heymann 	app->pf->dump_flag = val->flag;
1581d79e19f5SCarl Heymann 	app->pf->dump_len = len;
1582af623682SJakub Kicinski 
1583af623682SJakub Kicinski 	return 0;
1584af623682SJakub Kicinski }
1585af623682SJakub Kicinski 
1586af623682SJakub Kicinski static int
nfp_app_get_dump_flag(struct net_device * netdev,struct ethtool_dump * dump)1587a2f4c3d9SJakub Kicinski nfp_app_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1588af623682SJakub Kicinski {
1589d79e19f5SCarl Heymann 	struct nfp_app *app = nfp_app_from_netdev(netdev);
1590d79e19f5SCarl Heymann 
1591d79e19f5SCarl Heymann 	if (!app)
1592d79e19f5SCarl Heymann 		return -EOPNOTSUPP;
1593d79e19f5SCarl Heymann 
1594d79e19f5SCarl Heymann 	if (app->pf->dump_flag == NFP_DUMP_NSP_DIAG)
1595d79e19f5SCarl Heymann 		return nfp_dump_nsp_diag(app, dump, NULL);
1596d79e19f5SCarl Heymann 
1597d79e19f5SCarl Heymann 	dump->flag = app->pf->dump_flag;
1598d79e19f5SCarl Heymann 	dump->len = app->pf->dump_len;
1599d79e19f5SCarl Heymann 
1600d79e19f5SCarl Heymann 	return 0;
1601af623682SJakub Kicinski }
1602af623682SJakub Kicinski 
1603af623682SJakub Kicinski static int
nfp_app_get_dump_data(struct net_device * netdev,struct ethtool_dump * dump,void * buffer)1604a2f4c3d9SJakub Kicinski nfp_app_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1605af623682SJakub Kicinski 		      void *buffer)
1606af623682SJakub Kicinski {
1607d79e19f5SCarl Heymann 	struct nfp_app *app = nfp_app_from_netdev(netdev);
1608d79e19f5SCarl Heymann 
1609d79e19f5SCarl Heymann 	if (!app)
1610d79e19f5SCarl Heymann 		return -EOPNOTSUPP;
1611d79e19f5SCarl Heymann 
1612d79e19f5SCarl Heymann 	if (app->pf->dump_flag == NFP_DUMP_NSP_DIAG)
1613d79e19f5SCarl Heymann 		return nfp_dump_nsp_diag(app, dump, buffer);
1614d79e19f5SCarl Heymann 
1615d79e19f5SCarl Heymann 	dump->flag = app->pf->dump_flag;
1616d79e19f5SCarl Heymann 	dump->len = app->pf->dump_len;
1617d79e19f5SCarl Heymann 
1618d79e19f5SCarl Heymann 	return nfp_net_dump_populate_buffer(app->pf, app->pf->dumpspec, dump,
1619d79e19f5SCarl Heymann 					    buffer);
1620af623682SJakub Kicinski }
1621af623682SJakub Kicinski 
162261f7c6f4SDirk van der Merwe static int
nfp_port_get_module_info(struct net_device * netdev,struct ethtool_modinfo * modinfo)162361f7c6f4SDirk van der Merwe nfp_port_get_module_info(struct net_device *netdev,
162461f7c6f4SDirk van der Merwe 			 struct ethtool_modinfo *modinfo)
162561f7c6f4SDirk van der Merwe {
162661f7c6f4SDirk van der Merwe 	struct nfp_eth_table_port *eth_port;
162761f7c6f4SDirk van der Merwe 	struct nfp_port *port;
162861f7c6f4SDirk van der Merwe 	unsigned int read_len;
162961f7c6f4SDirk van der Merwe 	struct nfp_nsp *nsp;
163061f7c6f4SDirk van der Merwe 	int err = 0;
163161f7c6f4SDirk van der Merwe 	u8 data;
163261f7c6f4SDirk van der Merwe 
163361f7c6f4SDirk van der Merwe 	port = nfp_port_from_netdev(netdev);
16340873016dSJaco Coetzee 	if (!port)
16350873016dSJaco Coetzee 		return -EOPNOTSUPP;
16360873016dSJaco Coetzee 
16374ae97caeSYu Xiao 	/* update port state to get latest interface */
16384ae97caeSYu Xiao 	set_bit(NFP_PORT_CHANGED, &port->flags);
163961f7c6f4SDirk van der Merwe 	eth_port = nfp_port_get_eth_port(port);
164061f7c6f4SDirk van der Merwe 	if (!eth_port)
164161f7c6f4SDirk van der Merwe 		return -EOPNOTSUPP;
164261f7c6f4SDirk van der Merwe 
164361f7c6f4SDirk van der Merwe 	nsp = nfp_nsp_open(port->app->cpp);
164461f7c6f4SDirk van der Merwe 	if (IS_ERR(nsp)) {
164561f7c6f4SDirk van der Merwe 		err = PTR_ERR(nsp);
164661f7c6f4SDirk van der Merwe 		netdev_err(netdev, "Failed to access the NSP: %d\n", err);
164761f7c6f4SDirk van der Merwe 		return err;
164861f7c6f4SDirk van der Merwe 	}
164961f7c6f4SDirk van der Merwe 
165061f7c6f4SDirk van der Merwe 	if (!nfp_nsp_has_read_module_eeprom(nsp)) {
165161f7c6f4SDirk van der Merwe 		netdev_info(netdev, "reading module EEPROM not supported. Please update flash\n");
165261f7c6f4SDirk van der Merwe 		err = -EOPNOTSUPP;
165361f7c6f4SDirk van der Merwe 		goto exit_close_nsp;
165461f7c6f4SDirk van der Merwe 	}
165561f7c6f4SDirk van der Merwe 
165661f7c6f4SDirk van der Merwe 	switch (eth_port->interface) {
165761f7c6f4SDirk van der Merwe 	case NFP_INTERFACE_SFP:
165861f7c6f4SDirk van der Merwe 	case NFP_INTERFACE_SFP28:
165961f7c6f4SDirk van der Merwe 		err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
166061f7c6f4SDirk van der Merwe 						 SFP_SFF8472_COMPLIANCE, &data,
166161f7c6f4SDirk van der Merwe 						 1, &read_len);
166261f7c6f4SDirk van der Merwe 		if (err < 0)
166361f7c6f4SDirk van der Merwe 			goto exit_close_nsp;
166461f7c6f4SDirk van der Merwe 
166561f7c6f4SDirk van der Merwe 		if (!data) {
166661f7c6f4SDirk van der Merwe 			modinfo->type = ETH_MODULE_SFF_8079;
166761f7c6f4SDirk van der Merwe 			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
166861f7c6f4SDirk van der Merwe 		} else {
166961f7c6f4SDirk van der Merwe 			modinfo->type = ETH_MODULE_SFF_8472;
167061f7c6f4SDirk van der Merwe 			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
167161f7c6f4SDirk van der Merwe 		}
167261f7c6f4SDirk van der Merwe 		break;
167361f7c6f4SDirk van der Merwe 	case NFP_INTERFACE_QSFP:
167461f7c6f4SDirk van der Merwe 		err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
167561f7c6f4SDirk van der Merwe 						 SFP_SFF_REV_COMPLIANCE, &data,
167661f7c6f4SDirk van der Merwe 						 1, &read_len);
167761f7c6f4SDirk van der Merwe 		if (err < 0)
167861f7c6f4SDirk van der Merwe 			goto exit_close_nsp;
167961f7c6f4SDirk van der Merwe 
168061f7c6f4SDirk van der Merwe 		if (data < 0x3) {
168161f7c6f4SDirk van der Merwe 			modinfo->type = ETH_MODULE_SFF_8436;
1682f3a72878SJaco Coetzee 			modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
168361f7c6f4SDirk van der Merwe 		} else {
168461f7c6f4SDirk van der Merwe 			modinfo->type = ETH_MODULE_SFF_8636;
1685f3a72878SJaco Coetzee 			modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
168661f7c6f4SDirk van der Merwe 		}
168761f7c6f4SDirk van der Merwe 		break;
168861f7c6f4SDirk van der Merwe 	case NFP_INTERFACE_QSFP28:
168961f7c6f4SDirk van der Merwe 		modinfo->type = ETH_MODULE_SFF_8636;
1690f3a72878SJaco Coetzee 		modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
169161f7c6f4SDirk van der Merwe 		break;
169261f7c6f4SDirk van der Merwe 	default:
169361f7c6f4SDirk van der Merwe 		netdev_err(netdev, "Unsupported module 0x%x detected\n",
169461f7c6f4SDirk van der Merwe 			   eth_port->interface);
169561f7c6f4SDirk van der Merwe 		err = -EINVAL;
169661f7c6f4SDirk van der Merwe 	}
169761f7c6f4SDirk van der Merwe 
169861f7c6f4SDirk van der Merwe exit_close_nsp:
169961f7c6f4SDirk van der Merwe 	nfp_nsp_close(nsp);
170061f7c6f4SDirk van der Merwe 	return err;
170161f7c6f4SDirk van der Merwe }
170261f7c6f4SDirk van der Merwe 
170361f7c6f4SDirk van der Merwe static int
nfp_port_get_module_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * data)170461f7c6f4SDirk van der Merwe nfp_port_get_module_eeprom(struct net_device *netdev,
170561f7c6f4SDirk van der Merwe 			   struct ethtool_eeprom *eeprom, u8 *data)
170661f7c6f4SDirk van der Merwe {
170761f7c6f4SDirk van der Merwe 	struct nfp_eth_table_port *eth_port;
170861f7c6f4SDirk van der Merwe 	struct nfp_port *port;
170961f7c6f4SDirk van der Merwe 	struct nfp_nsp *nsp;
171061f7c6f4SDirk van der Merwe 	int err;
171161f7c6f4SDirk van der Merwe 
171261f7c6f4SDirk van der Merwe 	port = nfp_port_from_netdev(netdev);
171361f7c6f4SDirk van der Merwe 	eth_port = __nfp_port_get_eth_port(port);
171461f7c6f4SDirk van der Merwe 	if (!eth_port)
171561f7c6f4SDirk van der Merwe 		return -EOPNOTSUPP;
171661f7c6f4SDirk van der Merwe 
171761f7c6f4SDirk van der Merwe 	nsp = nfp_nsp_open(port->app->cpp);
171861f7c6f4SDirk van der Merwe 	if (IS_ERR(nsp)) {
171961f7c6f4SDirk van der Merwe 		err = PTR_ERR(nsp);
172061f7c6f4SDirk van der Merwe 		netdev_err(netdev, "Failed to access the NSP: %d\n", err);
172161f7c6f4SDirk van der Merwe 		return err;
172261f7c6f4SDirk van der Merwe 	}
172361f7c6f4SDirk van der Merwe 
172461f7c6f4SDirk van der Merwe 	if (!nfp_nsp_has_read_module_eeprom(nsp)) {
172561f7c6f4SDirk van der Merwe 		netdev_info(netdev, "reading module EEPROM not supported. Please update flash\n");
172661f7c6f4SDirk van der Merwe 		err = -EOPNOTSUPP;
172761f7c6f4SDirk van der Merwe 		goto exit_close_nsp;
172861f7c6f4SDirk van der Merwe 	}
172961f7c6f4SDirk van der Merwe 
173061f7c6f4SDirk van der Merwe 	err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
173161f7c6f4SDirk van der Merwe 					 eeprom->offset, data, eeprom->len,
173261f7c6f4SDirk van der Merwe 					 &eeprom->len);
173361f7c6f4SDirk van der Merwe 	if (err < 0) {
173461f7c6f4SDirk van der Merwe 		if (eeprom->len) {
173561f7c6f4SDirk van der Merwe 			netdev_warn(netdev,
173661f7c6f4SDirk van der Merwe 				    "Incomplete read from module EEPROM: %d\n",
173761f7c6f4SDirk van der Merwe 				     err);
173861f7c6f4SDirk van der Merwe 			err = 0;
173961f7c6f4SDirk van der Merwe 		} else {
174061f7c6f4SDirk van der Merwe 			netdev_err(netdev,
174161f7c6f4SDirk van der Merwe 				   "Reading from module EEPROM failed: %d\n",
174261f7c6f4SDirk van der Merwe 				   err);
174361f7c6f4SDirk van der Merwe 		}
174461f7c6f4SDirk van der Merwe 	}
174561f7c6f4SDirk van der Merwe 
174661f7c6f4SDirk van der Merwe exit_close_nsp:
174761f7c6f4SDirk van der Merwe 	nfp_nsp_close(nsp);
174861f7c6f4SDirk van der Merwe 	return err;
174961f7c6f4SDirk van der Merwe }
175061f7c6f4SDirk van der Merwe 
nfp_net_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)17514c352362SJakub Kicinski static int nfp_net_set_coalesce(struct net_device *netdev,
1752f3ccfda1SYufeng Mo 				struct ethtool_coalesce *ec,
1753f3ccfda1SYufeng Mo 				struct kernel_ethtool_coalesce *kernel_coal,
1754f3ccfda1SYufeng Mo 				struct netlink_ext_ack *extack)
17554c352362SJakub Kicinski {
17564c352362SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
17574c352362SJakub Kicinski 	unsigned int factor;
17584c352362SJakub Kicinski 
17594c352362SJakub Kicinski 	/* Compute factor used to convert coalesce '_usecs' parameters to
17604c352362SJakub Kicinski 	 * ME timestamp ticks.  There are 16 ME clock cycles for each timestamp
17614c352362SJakub Kicinski 	 * count.
17624c352362SJakub Kicinski 	 */
17633bd6b2a8SDiana Wang 	factor = nn->tlv_caps.me_freq_mhz / 16;
17644c352362SJakub Kicinski 
17654c352362SJakub Kicinski 	/* Each pair of (usecs, max_frames) fields specifies that interrupts
17664c352362SJakub Kicinski 	 * should be coalesced until
17674c352362SJakub Kicinski 	 *      (usecs > 0 && time_since_first_completion >= usecs) ||
17684c352362SJakub Kicinski 	 *      (max_frames > 0 && completed_frames >= max_frames)
17694c352362SJakub Kicinski 	 *
17704c352362SJakub Kicinski 	 * It is illegal to set both usecs and max_frames to zero as this would
17714c352362SJakub Kicinski 	 * cause interrupts to never be generated.  To disable coalescing, set
17724c352362SJakub Kicinski 	 * usecs = 0 and max_frames = 1.
17734c352362SJakub Kicinski 	 *
17744c352362SJakub Kicinski 	 * Some implementations ignore the value of max_frames and use the
17754c352362SJakub Kicinski 	 * condition time_since_first_completion >= usecs
17764c352362SJakub Kicinski 	 */
17774c352362SJakub Kicinski 
17784c352362SJakub Kicinski 	if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
17794c352362SJakub Kicinski 		return -EINVAL;
17804c352362SJakub Kicinski 
17814c352362SJakub Kicinski 	/* ensure valid configuration */
17824c352362SJakub Kicinski 	if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames)
17834c352362SJakub Kicinski 		return -EINVAL;
17844c352362SJakub Kicinski 
17854c352362SJakub Kicinski 	if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames)
17864c352362SJakub Kicinski 		return -EINVAL;
17874c352362SJakub Kicinski 
17889d32e4e7SYinjun Zhang 	if (nfp_net_coalesce_para_check(ec->rx_coalesce_usecs * factor,
17899d32e4e7SYinjun Zhang 					ec->rx_max_coalesced_frames))
17904c352362SJakub Kicinski 		return -EINVAL;
17914c352362SJakub Kicinski 
17929d32e4e7SYinjun Zhang 	if (nfp_net_coalesce_para_check(ec->tx_coalesce_usecs * factor,
17939d32e4e7SYinjun Zhang 					ec->tx_max_coalesced_frames))
17944c352362SJakub Kicinski 		return -EINVAL;
17954c352362SJakub Kicinski 
17964c352362SJakub Kicinski 	/* configuration is valid */
17979d32e4e7SYinjun Zhang 	nn->rx_coalesce_adapt_on = !!ec->use_adaptive_rx_coalesce;
17989d32e4e7SYinjun Zhang 	nn->tx_coalesce_adapt_on = !!ec->use_adaptive_tx_coalesce;
17999d32e4e7SYinjun Zhang 
18004c352362SJakub Kicinski 	nn->rx_coalesce_usecs      = ec->rx_coalesce_usecs;
18014c352362SJakub Kicinski 	nn->rx_coalesce_max_frames = ec->rx_max_coalesced_frames;
18024c352362SJakub Kicinski 	nn->tx_coalesce_usecs      = ec->tx_coalesce_usecs;
18034c352362SJakub Kicinski 	nn->tx_coalesce_max_frames = ec->tx_max_coalesced_frames;
18044c352362SJakub Kicinski 
18054c352362SJakub Kicinski 	/* write configuration to device */
18064c352362SJakub Kicinski 	nfp_net_coalesce_write_cfg(nn);
18074c352362SJakub Kicinski 	return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_IRQMOD);
18084c352362SJakub Kicinski }
18094c352362SJakub Kicinski 
nfp_net_get_channels(struct net_device * netdev,struct ethtool_channels * channel)181081cc2e43SJakub Kicinski static void nfp_net_get_channels(struct net_device *netdev,
181181cc2e43SJakub Kicinski 				 struct ethtool_channels *channel)
181281cc2e43SJakub Kicinski {
181381cc2e43SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
1814ecd63a02SJakub Kicinski 	unsigned int num_tx_rings;
1815ecd63a02SJakub Kicinski 
181679c12a75SJakub Kicinski 	num_tx_rings = nn->dp.num_tx_rings;
181779c12a75SJakub Kicinski 	if (nn->dp.xdp_prog)
181879c12a75SJakub Kicinski 		num_tx_rings -= nn->dp.num_rx_rings;
181981cc2e43SJakub Kicinski 
182081cc2e43SJakub Kicinski 	channel->max_rx = min(nn->max_rx_rings, nn->max_r_vecs);
182181cc2e43SJakub Kicinski 	channel->max_tx = min(nn->max_tx_rings, nn->max_r_vecs);
182281cc2e43SJakub Kicinski 	channel->max_combined = min(channel->max_rx, channel->max_tx);
182381cc2e43SJakub Kicinski 	channel->max_other = NFP_NET_NON_Q_VECTORS;
182479c12a75SJakub Kicinski 	channel->combined_count = min(nn->dp.num_rx_rings, num_tx_rings);
182579c12a75SJakub Kicinski 	channel->rx_count = nn->dp.num_rx_rings - channel->combined_count;
1826ecd63a02SJakub Kicinski 	channel->tx_count = num_tx_rings - channel->combined_count;
182781cc2e43SJakub Kicinski 	channel->other_count = NFP_NET_NON_Q_VECTORS;
182881cc2e43SJakub Kicinski }
182981cc2e43SJakub Kicinski 
nfp_net_set_num_rings(struct nfp_net * nn,unsigned int total_rx,unsigned int total_tx)1830164d1e9eSJakub Kicinski static int nfp_net_set_num_rings(struct nfp_net *nn, unsigned int total_rx,
1831164d1e9eSJakub Kicinski 				 unsigned int total_tx)
1832164d1e9eSJakub Kicinski {
1833783496b0SJakub Kicinski 	struct nfp_net_dp *dp;
1834164d1e9eSJakub Kicinski 
1835783496b0SJakub Kicinski 	dp = nfp_net_clone_dp(nn);
1836783496b0SJakub Kicinski 	if (!dp)
1837783496b0SJakub Kicinski 		return -ENOMEM;
1838783496b0SJakub Kicinski 
1839892a7f70SJakub Kicinski 	dp->num_rx_rings = total_rx;
1840892a7f70SJakub Kicinski 	dp->num_tx_rings = total_tx;
1841892a7f70SJakub Kicinski 	/* nfp_net_check_config() will catch num_tx_rings > nn->max_tx_rings */
1842892a7f70SJakub Kicinski 	if (dp->xdp_prog)
1843892a7f70SJakub Kicinski 		dp->num_tx_rings += total_rx;
1844892a7f70SJakub Kicinski 
1845d957c0f7SJakub Kicinski 	return nfp_net_ring_reconfig(nn, dp, NULL);
1846164d1e9eSJakub Kicinski }
1847164d1e9eSJakub Kicinski 
nfp_net_set_channels(struct net_device * netdev,struct ethtool_channels * channel)1848164d1e9eSJakub Kicinski static int nfp_net_set_channels(struct net_device *netdev,
1849164d1e9eSJakub Kicinski 				struct ethtool_channels *channel)
1850164d1e9eSJakub Kicinski {
1851164d1e9eSJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
1852164d1e9eSJakub Kicinski 	unsigned int total_rx, total_tx;
1853164d1e9eSJakub Kicinski 
1854164d1e9eSJakub Kicinski 	/* Reject unsupported */
18554df6ff2aSJakub Kicinski 	if (channel->other_count != NFP_NET_NON_Q_VECTORS ||
1856164d1e9eSJakub Kicinski 	    (channel->rx_count && channel->tx_count))
1857164d1e9eSJakub Kicinski 		return -EINVAL;
1858164d1e9eSJakub Kicinski 
1859164d1e9eSJakub Kicinski 	total_rx = channel->combined_count + channel->rx_count;
1860164d1e9eSJakub Kicinski 	total_tx = channel->combined_count + channel->tx_count;
1861164d1e9eSJakub Kicinski 
1862164d1e9eSJakub Kicinski 	if (total_rx > min(nn->max_rx_rings, nn->max_r_vecs) ||
1863164d1e9eSJakub Kicinski 	    total_tx > min(nn->max_tx_rings, nn->max_r_vecs))
1864164d1e9eSJakub Kicinski 		return -EINVAL;
1865164d1e9eSJakub Kicinski 
1866164d1e9eSJakub Kicinski 	return nfp_net_set_num_rings(nn, total_rx, total_tx);
1867164d1e9eSJakub Kicinski }
1868164d1e9eSJakub Kicinski 
nfp_port_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)1869382f99c4SYinjun Zhang static void nfp_port_get_pauseparam(struct net_device *netdev,
1870382f99c4SYinjun Zhang 				    struct ethtool_pauseparam *pause)
1871382f99c4SYinjun Zhang {
1872382f99c4SYinjun Zhang 	struct nfp_eth_table_port *eth_port;
1873382f99c4SYinjun Zhang 	struct nfp_port *port;
1874382f99c4SYinjun Zhang 
1875382f99c4SYinjun Zhang 	port = nfp_port_from_netdev(netdev);
1876382f99c4SYinjun Zhang 	eth_port = nfp_port_get_eth_port(port);
1877382f99c4SYinjun Zhang 	if (!eth_port)
1878382f99c4SYinjun Zhang 		return;
1879382f99c4SYinjun Zhang 
1880382f99c4SYinjun Zhang 	/* Currently pause frame support is fixed */
1881382f99c4SYinjun Zhang 	pause->autoneg = AUTONEG_DISABLE;
1882382f99c4SYinjun Zhang 	pause->rx_pause = 1;
1883382f99c4SYinjun Zhang 	pause->tx_pause = 1;
1884382f99c4SYinjun Zhang }
1885382f99c4SYinjun Zhang 
nfp_net_set_phys_id(struct net_device * netdev,enum ethtool_phys_id_state state)1886ccb9bc1dSSixiang Chen static int nfp_net_set_phys_id(struct net_device *netdev,
1887ccb9bc1dSSixiang Chen 			       enum ethtool_phys_id_state state)
1888ccb9bc1dSSixiang Chen {
1889ccb9bc1dSSixiang Chen 	struct nfp_eth_table_port *eth_port;
1890ccb9bc1dSSixiang Chen 	struct nfp_port *port;
1891ccb9bc1dSSixiang Chen 	int err;
1892ccb9bc1dSSixiang Chen 
1893ccb9bc1dSSixiang Chen 	port = nfp_port_from_netdev(netdev);
1894ccb9bc1dSSixiang Chen 	eth_port = __nfp_port_get_eth_port(port);
1895ccb9bc1dSSixiang Chen 	if (!eth_port)
1896ccb9bc1dSSixiang Chen 		return -EOPNOTSUPP;
1897ccb9bc1dSSixiang Chen 
1898ccb9bc1dSSixiang Chen 	switch (state) {
1899ccb9bc1dSSixiang Chen 	case ETHTOOL_ID_ACTIVE:
1900ccb9bc1dSSixiang Chen 		/* Control LED to blink */
1901ccb9bc1dSSixiang Chen 		err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 1);
1902ccb9bc1dSSixiang Chen 		break;
1903ccb9bc1dSSixiang Chen 
1904ccb9bc1dSSixiang Chen 	case ETHTOOL_ID_INACTIVE:
1905ccb9bc1dSSixiang Chen 		/* Control LED to normal mode */
1906ccb9bc1dSSixiang Chen 		err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 0);
1907ccb9bc1dSSixiang Chen 		break;
1908ccb9bc1dSSixiang Chen 
1909ccb9bc1dSSixiang Chen 	case ETHTOOL_ID_ON:
1910ccb9bc1dSSixiang Chen 	case ETHTOOL_ID_OFF:
1911ccb9bc1dSSixiang Chen 	default:
1912ccb9bc1dSSixiang Chen 		return -EOPNOTSUPP;
1913ccb9bc1dSSixiang Chen 	}
1914ccb9bc1dSSixiang Chen 
1915ccb9bc1dSSixiang Chen 	return err;
1916ccb9bc1dSSixiang Chen }
1917ccb9bc1dSSixiang Chen 
1918e6686745SBaowen Zheng #define NFP_EEPROM_LEN ETH_ALEN
1919e6686745SBaowen Zheng 
1920e6686745SBaowen Zheng static int
nfp_net_get_eeprom_len(struct net_device * netdev)1921e6686745SBaowen Zheng nfp_net_get_eeprom_len(struct net_device *netdev)
1922e6686745SBaowen Zheng {
1923e6686745SBaowen Zheng 	struct nfp_eth_table_port *eth_port;
1924e6686745SBaowen Zheng 	struct nfp_port *port;
1925e6686745SBaowen Zheng 
1926e6686745SBaowen Zheng 	port = nfp_port_from_netdev(netdev);
1927e6686745SBaowen Zheng 	eth_port = __nfp_port_get_eth_port(port);
1928e6686745SBaowen Zheng 	if (!eth_port)
1929e6686745SBaowen Zheng 		return 0;
1930e6686745SBaowen Zheng 
1931e6686745SBaowen Zheng 	return NFP_EEPROM_LEN;
1932e6686745SBaowen Zheng }
1933e6686745SBaowen Zheng 
1934e6686745SBaowen Zheng static int
nfp_net_get_nsp_hwindex(struct net_device * netdev,struct nfp_nsp ** nspptr,u32 * index)1935e6686745SBaowen Zheng nfp_net_get_nsp_hwindex(struct net_device *netdev,
1936e6686745SBaowen Zheng 			struct nfp_nsp **nspptr,
1937e6686745SBaowen Zheng 			u32 *index)
1938e6686745SBaowen Zheng {
1939e6686745SBaowen Zheng 	struct nfp_eth_table_port *eth_port;
1940e6686745SBaowen Zheng 	struct nfp_port *port;
1941e6686745SBaowen Zheng 	struct nfp_nsp *nsp;
1942e6686745SBaowen Zheng 	int err;
1943e6686745SBaowen Zheng 
1944e6686745SBaowen Zheng 	port = nfp_port_from_netdev(netdev);
1945e6686745SBaowen Zheng 	eth_port = __nfp_port_get_eth_port(port);
1946e6686745SBaowen Zheng 	if (!eth_port)
1947e6686745SBaowen Zheng 		return -EOPNOTSUPP;
1948e6686745SBaowen Zheng 
1949e6686745SBaowen Zheng 	nsp = nfp_nsp_open(port->app->cpp);
1950e6686745SBaowen Zheng 	if (IS_ERR(nsp)) {
1951e6686745SBaowen Zheng 		err = PTR_ERR(nsp);
1952e6686745SBaowen Zheng 		netdev_err(netdev, "Failed to access the NSP: %d\n", err);
1953e6686745SBaowen Zheng 		return err;
1954e6686745SBaowen Zheng 	}
1955e6686745SBaowen Zheng 
1956e6686745SBaowen Zheng 	if (!nfp_nsp_has_hwinfo_lookup(nsp)) {
1957e6686745SBaowen Zheng 		netdev_err(netdev, "NSP doesn't support PF MAC generation\n");
1958e6686745SBaowen Zheng 		nfp_nsp_close(nsp);
1959e6686745SBaowen Zheng 		return -EOPNOTSUPP;
1960e6686745SBaowen Zheng 	}
1961e6686745SBaowen Zheng 
1962e6686745SBaowen Zheng 	*nspptr = nsp;
1963e6686745SBaowen Zheng 	*index = eth_port->eth_index;
1964e6686745SBaowen Zheng 
1965e6686745SBaowen Zheng 	return 0;
1966e6686745SBaowen Zheng }
1967e6686745SBaowen Zheng 
1968e6686745SBaowen Zheng static int
nfp_net_get_port_mac_by_hwinfo(struct net_device * netdev,u8 * mac_addr)1969e6686745SBaowen Zheng nfp_net_get_port_mac_by_hwinfo(struct net_device *netdev,
1970e6686745SBaowen Zheng 			       u8 *mac_addr)
1971e6686745SBaowen Zheng {
1972e6686745SBaowen Zheng 	char hwinfo[32] = {};
1973e6686745SBaowen Zheng 	struct nfp_nsp *nsp;
1974e6686745SBaowen Zheng 	u32 index;
1975e6686745SBaowen Zheng 	int err;
1976e6686745SBaowen Zheng 
1977e6686745SBaowen Zheng 	err = nfp_net_get_nsp_hwindex(netdev, &nsp, &index);
1978e6686745SBaowen Zheng 	if (err)
1979e6686745SBaowen Zheng 		return err;
1980e6686745SBaowen Zheng 
1981e6686745SBaowen Zheng 	snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac", index);
1982e6686745SBaowen Zheng 	err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo));
1983e6686745SBaowen Zheng 	nfp_nsp_close(nsp);
1984e6686745SBaowen Zheng 	if (err) {
1985e6686745SBaowen Zheng 		netdev_err(netdev, "Reading persistent MAC address failed: %d\n",
1986e6686745SBaowen Zheng 			   err);
1987e6686745SBaowen Zheng 		return -EOPNOTSUPP;
1988e6686745SBaowen Zheng 	}
1989e6686745SBaowen Zheng 
1990e6686745SBaowen Zheng 	if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1991e6686745SBaowen Zheng 		   &mac_addr[0], &mac_addr[1], &mac_addr[2],
1992e6686745SBaowen Zheng 		   &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
1993e6686745SBaowen Zheng 		netdev_err(netdev, "Can't parse persistent MAC address (%s)\n",
1994e6686745SBaowen Zheng 			   hwinfo);
1995e6686745SBaowen Zheng 		return -EOPNOTSUPP;
1996e6686745SBaowen Zheng 	}
1997e6686745SBaowen Zheng 
1998e6686745SBaowen Zheng 	return 0;
1999e6686745SBaowen Zheng }
2000e6686745SBaowen Zheng 
2001e6686745SBaowen Zheng static int
nfp_net_set_port_mac_by_hwinfo(struct net_device * netdev,u8 * mac_addr)2002e6686745SBaowen Zheng nfp_net_set_port_mac_by_hwinfo(struct net_device *netdev,
2003e6686745SBaowen Zheng 			       u8 *mac_addr)
2004e6686745SBaowen Zheng {
2005e6686745SBaowen Zheng 	char hwinfo[32] = {};
2006e6686745SBaowen Zheng 	struct nfp_nsp *nsp;
2007e6686745SBaowen Zheng 	u32 index;
2008e6686745SBaowen Zheng 	int err;
2009e6686745SBaowen Zheng 
2010e6686745SBaowen Zheng 	err = nfp_net_get_nsp_hwindex(netdev, &nsp, &index);
2011e6686745SBaowen Zheng 	if (err)
2012e6686745SBaowen Zheng 		return err;
2013e6686745SBaowen Zheng 
2014e6686745SBaowen Zheng 	snprintf(hwinfo, sizeof(hwinfo),
2015e6686745SBaowen Zheng 		 "eth%u.mac=%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2016e6686745SBaowen Zheng 		 index, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
2017e6686745SBaowen Zheng 		 mac_addr[4], mac_addr[5]);
2018e6686745SBaowen Zheng 
2019e6686745SBaowen Zheng 	err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
2020e6686745SBaowen Zheng 	nfp_nsp_close(nsp);
2021e6686745SBaowen Zheng 	if (err) {
2022e6686745SBaowen Zheng 		netdev_err(netdev, "HWinfo set failed: %d, hwinfo: %s\n",
2023e6686745SBaowen Zheng 			   err, hwinfo);
2024e6686745SBaowen Zheng 		return -EOPNOTSUPP;
2025e6686745SBaowen Zheng 	}
2026e6686745SBaowen Zheng 
2027e6686745SBaowen Zheng 	return 0;
2028e6686745SBaowen Zheng }
2029e6686745SBaowen Zheng 
2030e6686745SBaowen Zheng static int
nfp_net_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)2031e6686745SBaowen Zheng nfp_net_get_eeprom(struct net_device *netdev,
2032e6686745SBaowen Zheng 		   struct ethtool_eeprom *eeprom, u8 *bytes)
2033e6686745SBaowen Zheng {
203474b4f173SJames Hershaw 	struct nfp_app *app = nfp_app_from_netdev(netdev);
2035e6686745SBaowen Zheng 	u8 buf[NFP_EEPROM_LEN] = {};
2036e6686745SBaowen Zheng 
2037e6686745SBaowen Zheng 	if (nfp_net_get_port_mac_by_hwinfo(netdev, buf))
2038e6686745SBaowen Zheng 		return -EOPNOTSUPP;
2039e6686745SBaowen Zheng 
2040f8175547SJames Hershaw 	if (eeprom->len == 0)
2041f8175547SJames Hershaw 		return -EINVAL;
2042f8175547SJames Hershaw 
204374b4f173SJames Hershaw 	eeprom->magic = app->pdev->vendor | (app->pdev->device << 16);
2044e6686745SBaowen Zheng 	memcpy(bytes, buf + eeprom->offset, eeprom->len);
2045e6686745SBaowen Zheng 
2046e6686745SBaowen Zheng 	return 0;
2047e6686745SBaowen Zheng }
2048e6686745SBaowen Zheng 
2049e6686745SBaowen Zheng static int
nfp_net_set_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)2050e6686745SBaowen Zheng nfp_net_set_eeprom(struct net_device *netdev,
2051e6686745SBaowen Zheng 		   struct ethtool_eeprom *eeprom, u8 *bytes)
2052e6686745SBaowen Zheng {
205374b4f173SJames Hershaw 	struct nfp_app *app = nfp_app_from_netdev(netdev);
2054e6686745SBaowen Zheng 	u8 buf[NFP_EEPROM_LEN] = {};
2055e6686745SBaowen Zheng 
2056f8175547SJames Hershaw 	if (nfp_net_get_port_mac_by_hwinfo(netdev, buf))
2057f8175547SJames Hershaw 		return -EOPNOTSUPP;
2058f8175547SJames Hershaw 
2059e6686745SBaowen Zheng 	if (eeprom->len == 0)
2060e6686745SBaowen Zheng 		return -EINVAL;
2061e6686745SBaowen Zheng 
206274b4f173SJames Hershaw 	if (eeprom->magic != (app->pdev->vendor | app->pdev->device << 16))
2063e6686745SBaowen Zheng 		return -EINVAL;
2064e6686745SBaowen Zheng 
2065e6686745SBaowen Zheng 	memcpy(buf + eeprom->offset, bytes, eeprom->len);
2066e6686745SBaowen Zheng 	if (nfp_net_set_port_mac_by_hwinfo(netdev, buf))
2067e6686745SBaowen Zheng 		return -EOPNOTSUPP;
2068e6686745SBaowen Zheng 
2069e6686745SBaowen Zheng 	return 0;
2070e6686745SBaowen Zheng }
2071e6686745SBaowen Zheng 
20724c352362SJakub Kicinski static const struct ethtool_ops nfp_net_ethtool_ops = {
20730e72ea19SJakub Kicinski 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
20749d32e4e7SYinjun Zhang 				     ETHTOOL_COALESCE_MAX_FRAMES |
20759d32e4e7SYinjun Zhang 				     ETHTOOL_COALESCE_USE_ADAPTIVE,
20764c352362SJakub Kicinski 	.get_drvinfo		= nfp_net_get_drvinfo,
20772820a400SFei Qin 	.nway_reset             = nfp_net_nway_reset,
20782370def2SJakub Kicinski 	.get_link		= ethtool_op_get_link,
20794c352362SJakub Kicinski 	.get_ringparam		= nfp_net_get_ringparam,
20804c352362SJakub Kicinski 	.set_ringparam		= nfp_net_set_ringparam,
208115137daeSFei Qin 	.self_test		= nfp_net_self_test,
20824c352362SJakub Kicinski 	.get_strings		= nfp_net_get_strings,
20834c352362SJakub Kicinski 	.get_ethtool_stats	= nfp_net_get_stats,
20844c352362SJakub Kicinski 	.get_sset_count		= nfp_net_get_sset_count,
20854c352362SJakub Kicinski 	.get_rxnfc		= nfp_net_get_rxnfc,
20864c352362SJakub Kicinski 	.set_rxnfc		= nfp_net_set_rxnfc,
20874c352362SJakub Kicinski 	.get_rxfh_indir_size	= nfp_net_get_rxfh_indir_size,
20884c352362SJakub Kicinski 	.get_rxfh_key_size	= nfp_net_get_rxfh_key_size,
20894c352362SJakub Kicinski 	.get_rxfh		= nfp_net_get_rxfh,
20904c352362SJakub Kicinski 	.set_rxfh		= nfp_net_set_rxfh,
20914c352362SJakub Kicinski 	.get_regs_len		= nfp_net_get_regs_len,
20924c352362SJakub Kicinski 	.get_regs		= nfp_net_get_regs,
2093a2f4c3d9SJakub Kicinski 	.set_dump		= nfp_app_set_dump,
2094a2f4c3d9SJakub Kicinski 	.get_dump_flag		= nfp_app_get_dump_flag,
2095a2f4c3d9SJakub Kicinski 	.get_dump_data		= nfp_app_get_dump_data,
2096e6686745SBaowen Zheng 	.get_eeprom_len         = nfp_net_get_eeprom_len,
2097e6686745SBaowen Zheng 	.get_eeprom             = nfp_net_get_eeprom,
2098e6686745SBaowen Zheng 	.set_eeprom             = nfp_net_set_eeprom,
209961f7c6f4SDirk van der Merwe 	.get_module_info	= nfp_port_get_module_info,
210061f7c6f4SDirk van der Merwe 	.get_module_eeprom	= nfp_port_get_module_eeprom,
21014c352362SJakub Kicinski 	.get_coalesce           = nfp_net_get_coalesce,
21024c352362SJakub Kicinski 	.set_coalesce           = nfp_net_set_coalesce,
210381cc2e43SJakub Kicinski 	.get_channels		= nfp_net_get_channels,
2104164d1e9eSJakub Kicinski 	.set_channels		= nfp_net_set_channels,
2105265aeb51SJakub Kicinski 	.get_link_ksettings	= nfp_net_get_link_ksettings,
21067c698737SJakub Kicinski 	.set_link_ksettings	= nfp_net_set_link_ksettings,
21070d087093SDirk van der Merwe 	.get_fecparam		= nfp_port_get_fecparam,
21080d087093SDirk van der Merwe 	.set_fecparam		= nfp_port_set_fecparam,
2109382f99c4SYinjun Zhang 	.get_pauseparam		= nfp_port_get_pauseparam,
2110ccb9bc1dSSixiang Chen 	.set_phys_id		= nfp_net_set_phys_id,
21114c352362SJakub Kicinski };
21124c352362SJakub Kicinski 
211306726f30SJakub Kicinski const struct ethtool_ops nfp_port_ethtool_ops = {
21149e4c2cfcSJakub Kicinski 	.get_drvinfo		= nfp_app_get_drvinfo,
21152820a400SFei Qin 	.nway_reset             = nfp_net_nway_reset,
211606726f30SJakub Kicinski 	.get_link		= ethtool_op_get_link,
2117899a37adSJakub Kicinski 	.get_strings		= nfp_port_get_strings,
2118899a37adSJakub Kicinski 	.get_ethtool_stats	= nfp_port_get_stats,
211915137daeSFei Qin 	.self_test		= nfp_net_self_test,
2120899a37adSJakub Kicinski 	.get_sset_count		= nfp_port_get_sset_count,
2121a2f4c3d9SJakub Kicinski 	.set_dump		= nfp_app_set_dump,
2122a2f4c3d9SJakub Kicinski 	.get_dump_flag		= nfp_app_get_dump_flag,
2123a2f4c3d9SJakub Kicinski 	.get_dump_data		= nfp_app_get_dump_data,
212474b4f173SJames Hershaw 	.get_eeprom_len         = nfp_net_get_eeprom_len,
212574b4f173SJames Hershaw 	.get_eeprom             = nfp_net_get_eeprom,
212674b4f173SJames Hershaw 	.set_eeprom             = nfp_net_set_eeprom,
212761f7c6f4SDirk van der Merwe 	.get_module_info	= nfp_port_get_module_info,
212861f7c6f4SDirk van der Merwe 	.get_module_eeprom	= nfp_port_get_module_eeprom,
2129a564d30eSDirk van der Merwe 	.get_link_ksettings	= nfp_net_get_link_ksettings,
2130a564d30eSDirk van der Merwe 	.set_link_ksettings	= nfp_net_set_link_ksettings,
21310d087093SDirk van der Merwe 	.get_fecparam		= nfp_port_get_fecparam,
21320d087093SDirk van der Merwe 	.set_fecparam		= nfp_port_set_fecparam,
2133382f99c4SYinjun Zhang 	.get_pauseparam		= nfp_port_get_pauseparam,
2134ccb9bc1dSSixiang Chen 	.set_phys_id		= nfp_net_set_phys_id,
213506726f30SJakub Kicinski };
213606726f30SJakub Kicinski 
nfp_net_set_ethtool_ops(struct net_device * netdev)21374c352362SJakub Kicinski void nfp_net_set_ethtool_ops(struct net_device *netdev)
21384c352362SJakub Kicinski {
21394c352362SJakub Kicinski 	netdev->ethtool_ops = &nfp_net_ethtool_ops;
21404c352362SJakub Kicinski }
2141