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) {
443a731a43eSYinjun 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
450a731a43eSYinjun 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 {
454a731a43eSYinjun 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
461a731a43eSYinjun 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 }
466a731a43eSYinjun Zhang
467a731a43eSYinjun Zhang /* We take all speeds as supported when it fails to read
468a731a43eSYinjun Zhang * link modes due to old management firmware that doesn't
469a731a43eSYinjun Zhang * support link modes reading or error occurring, so that
470a731a43eSYinjun Zhang * speed change of this port is allowed.
471a731a43eSYinjun Zhang */
472a731a43eSYinjun Zhang if (bitmap_empty(port->speed_bitmap, NFP_SUP_SPEED_NUMBER))
473a731a43eSYinjun 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,struct netlink_ext_ack * extack)636b0318e28SRyno Swart static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt,
637b0318e28SRyno Swart struct netlink_ext_ack *extack)
63868453c7aSJakub Kicinski {
639783496b0SJakub Kicinski struct nfp_net_dp *dp;
64068453c7aSJakub Kicinski
641783496b0SJakub Kicinski dp = nfp_net_clone_dp(nn);
642783496b0SJakub Kicinski if (!dp)
643783496b0SJakub Kicinski return -ENOMEM;
644783496b0SJakub Kicinski
645892a7f70SJakub Kicinski dp->rxd_cnt = rxd_cnt;
646892a7f70SJakub Kicinski dp->txd_cnt = txd_cnt;
647892a7f70SJakub Kicinski
648b0318e28SRyno Swart return nfp_net_ring_reconfig(nn, dp, extack);
64968453c7aSJakub Kicinski }
65068453c7aSJakub Kicinski
nfp_net_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)6514c352362SJakub Kicinski static int nfp_net_set_ringparam(struct net_device *netdev,
65274624944SHao Chen struct ethtool_ringparam *ring,
65374624944SHao Chen struct kernel_ethtool_ringparam *kernel_ring,
65474624944SHao Chen struct netlink_ext_ack *extack)
6554c352362SJakub Kicinski {
656d6488c49SJakub Kicinski u32 tx_dpp, qc_min, qc_max, rxd_cnt, txd_cnt;
6574c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
6584c352362SJakub Kicinski
6594c352362SJakub Kicinski /* We don't have separate queues/rings for small/large frames. */
6604c352362SJakub Kicinski if (ring->rx_mini_pending || ring->rx_jumbo_pending)
661b0318e28SRyno Swart return -EOPNOTSUPP;
6624c352362SJakub Kicinski
6637f3aa620SJakub Kicinski qc_min = nn->dev_info->min_qc_size;
6647f3aa620SJakub Kicinski qc_max = nn->dev_info->max_qc_size;
665d6488c49SJakub Kicinski tx_dpp = nn->dp.ops->tx_min_desc_per_pkt;
6664c352362SJakub Kicinski /* Round up to supported values */
6674c352362SJakub Kicinski rxd_cnt = roundup_pow_of_two(ring->rx_pending);
6684c352362SJakub Kicinski txd_cnt = roundup_pow_of_two(ring->tx_pending);
6694c352362SJakub Kicinski
670b0318e28SRyno Swart if (rxd_cnt < qc_min || rxd_cnt > qc_max) {
671b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack, "rx parameter out of bounds");
672cc7c0333SJakub Kicinski return -EINVAL;
673b0318e28SRyno Swart }
674b0318e28SRyno Swart
675b0318e28SRyno Swart if (txd_cnt < qc_min / tx_dpp || txd_cnt > qc_max / tx_dpp) {
676b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack, "tx parameter out of bounds");
677b0318e28SRyno Swart return -EINVAL;
678b0318e28SRyno Swart }
679cc7c0333SJakub Kicinski
68079c12a75SJakub Kicinski if (nn->dp.rxd_cnt == rxd_cnt && nn->dp.txd_cnt == txd_cnt)
681cc7c0333SJakub Kicinski return 0;
682cc7c0333SJakub Kicinski
6834c352362SJakub Kicinski nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n",
68479c12a75SJakub Kicinski nn->dp.rxd_cnt, rxd_cnt, nn->dp.txd_cnt, txd_cnt);
6854c352362SJakub Kicinski
686b0318e28SRyno Swart return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt, extack);
6874c352362SJakub Kicinski }
6884c352362SJakub Kicinski
nfp_test_link(struct net_device * netdev)68915137daeSFei Qin static int nfp_test_link(struct net_device *netdev)
69015137daeSFei Qin {
69115137daeSFei Qin if (!netif_carrier_ok(netdev) || !(netdev->flags & IFF_UP))
69215137daeSFei Qin return 1;
69315137daeSFei Qin
69415137daeSFei Qin return 0;
69515137daeSFei Qin }
69615137daeSFei Qin
nfp_test_nsp(struct net_device * netdev)69715137daeSFei Qin static int nfp_test_nsp(struct net_device *netdev)
69815137daeSFei Qin {
69915137daeSFei Qin struct nfp_app *app = nfp_app_from_netdev(netdev);
70015137daeSFei Qin struct nfp_nsp_identify *nspi;
70115137daeSFei Qin struct nfp_nsp *nsp;
70215137daeSFei Qin int err;
70315137daeSFei Qin
70415137daeSFei Qin nsp = nfp_nsp_open(app->cpp);
70515137daeSFei Qin if (IS_ERR(nsp)) {
70615137daeSFei Qin err = PTR_ERR(nsp);
70715137daeSFei Qin netdev_info(netdev, "NSP Test: failed to access the NSP: %d\n", err);
70815137daeSFei Qin goto exit;
70915137daeSFei Qin }
71015137daeSFei Qin
71115137daeSFei Qin if (nfp_nsp_get_abi_ver_minor(nsp) < 15) {
71215137daeSFei Qin err = -EOPNOTSUPP;
71315137daeSFei Qin goto exit_close_nsp;
71415137daeSFei Qin }
71515137daeSFei Qin
71615137daeSFei Qin nspi = kzalloc(sizeof(*nspi), GFP_KERNEL);
71715137daeSFei Qin if (!nspi) {
71815137daeSFei Qin err = -ENOMEM;
71915137daeSFei Qin goto exit_close_nsp;
72015137daeSFei Qin }
72115137daeSFei Qin
72215137daeSFei Qin err = nfp_nsp_read_identify(nsp, nspi, sizeof(*nspi));
72315137daeSFei Qin if (err < 0)
72415137daeSFei Qin netdev_info(netdev, "NSP Test: reading bsp version failed %d\n", err);
72515137daeSFei Qin
72615137daeSFei Qin kfree(nspi);
72715137daeSFei Qin exit_close_nsp:
72815137daeSFei Qin nfp_nsp_close(nsp);
72915137daeSFei Qin exit:
73015137daeSFei Qin return err;
73115137daeSFei Qin }
73215137daeSFei Qin
nfp_test_fw(struct net_device * netdev)73315137daeSFei Qin static int nfp_test_fw(struct net_device *netdev)
73415137daeSFei Qin {
73515137daeSFei Qin struct nfp_net *nn = netdev_priv(netdev);
73615137daeSFei Qin int err;
73715137daeSFei Qin
73815137daeSFei Qin err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN);
73915137daeSFei Qin if (err)
74015137daeSFei Qin netdev_info(netdev, "FW Test: update failed %d\n", err);
74115137daeSFei Qin
74215137daeSFei Qin return err;
74315137daeSFei Qin }
74415137daeSFei Qin
nfp_test_reg(struct net_device * netdev)74515137daeSFei Qin static int nfp_test_reg(struct net_device *netdev)
74615137daeSFei Qin {
74715137daeSFei Qin struct nfp_app *app = nfp_app_from_netdev(netdev);
74815137daeSFei Qin struct nfp_cpp *cpp = app->cpp;
74915137daeSFei Qin u32 model = nfp_cpp_model(cpp);
75015137daeSFei Qin u32 value;
75115137daeSFei Qin int err;
75215137daeSFei Qin
75315137daeSFei Qin err = nfp_cpp_model_autodetect(cpp, &value);
75415137daeSFei Qin if (err < 0) {
75515137daeSFei Qin netdev_info(netdev, "REG Test: NFP model detection failed %d\n", err);
75615137daeSFei Qin return err;
75715137daeSFei Qin }
75815137daeSFei Qin
75915137daeSFei Qin return (value == model) ? 0 : 1;
76015137daeSFei Qin }
76115137daeSFei Qin
link_test_supported(struct net_device * netdev)76215137daeSFei Qin static bool link_test_supported(struct net_device *netdev)
76315137daeSFei Qin {
76415137daeSFei Qin return true;
76515137daeSFei Qin }
76615137daeSFei Qin
nsp_test_supported(struct net_device * netdev)76715137daeSFei Qin static bool nsp_test_supported(struct net_device *netdev)
76815137daeSFei Qin {
76915137daeSFei Qin if (nfp_app_from_netdev(netdev))
77015137daeSFei Qin return true;
77115137daeSFei Qin
77215137daeSFei Qin return false;
77315137daeSFei Qin }
77415137daeSFei Qin
fw_test_supported(struct net_device * netdev)77515137daeSFei Qin static bool fw_test_supported(struct net_device *netdev)
77615137daeSFei Qin {
77715137daeSFei Qin if (nfp_netdev_is_nfp_net(netdev))
77815137daeSFei Qin return true;
77915137daeSFei Qin
78015137daeSFei Qin return false;
78115137daeSFei Qin }
78215137daeSFei Qin
reg_test_supported(struct net_device * netdev)78315137daeSFei Qin static bool reg_test_supported(struct net_device *netdev)
78415137daeSFei Qin {
78515137daeSFei Qin if (nfp_app_from_netdev(netdev))
78615137daeSFei Qin return true;
78715137daeSFei Qin
78815137daeSFei Qin return false;
78915137daeSFei Qin }
79015137daeSFei Qin
79115137daeSFei Qin static struct nfp_self_test_item {
79215137daeSFei Qin char name[ETH_GSTRING_LEN];
79315137daeSFei Qin bool (*is_supported)(struct net_device *dev);
79415137daeSFei Qin int (*func)(struct net_device *dev);
79515137daeSFei Qin } nfp_self_test[] = {
79615137daeSFei Qin {"Link Test", link_test_supported, nfp_test_link},
79715137daeSFei Qin {"NSP Test", nsp_test_supported, nfp_test_nsp},
79815137daeSFei Qin {"Firmware Test", fw_test_supported, nfp_test_fw},
79915137daeSFei Qin {"Register Test", reg_test_supported, nfp_test_reg}
80015137daeSFei Qin };
80115137daeSFei Qin
80215137daeSFei Qin #define NFP_TEST_TOTAL_NUM ARRAY_SIZE(nfp_self_test)
80315137daeSFei Qin
nfp_get_self_test_strings(struct net_device * netdev,u8 * data)80415137daeSFei Qin static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data)
80515137daeSFei Qin {
80615137daeSFei Qin int i;
80715137daeSFei Qin
80815137daeSFei Qin for (i = 0; i < NFP_TEST_TOTAL_NUM; i++)
80915137daeSFei Qin if (nfp_self_test[i].is_supported(netdev))
810e403cfffSjustinstitt@google.com ethtool_puts(&data, nfp_self_test[i].name);
81115137daeSFei Qin }
81215137daeSFei Qin
nfp_get_self_test_count(struct net_device * netdev)81315137daeSFei Qin static int nfp_get_self_test_count(struct net_device *netdev)
81415137daeSFei Qin {
81515137daeSFei Qin int i, count = 0;
81615137daeSFei Qin
81715137daeSFei Qin for (i = 0; i < NFP_TEST_TOTAL_NUM; i++)
81815137daeSFei Qin if (nfp_self_test[i].is_supported(netdev))
81915137daeSFei Qin count++;
82015137daeSFei Qin
82115137daeSFei Qin return count;
82215137daeSFei Qin }
82315137daeSFei Qin
nfp_net_self_test(struct net_device * netdev,struct ethtool_test * eth_test,u64 * data)82415137daeSFei Qin static void nfp_net_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
82515137daeSFei Qin u64 *data)
82615137daeSFei Qin {
82715137daeSFei Qin int i, ret, count = 0;
82815137daeSFei Qin
82915137daeSFei Qin netdev_info(netdev, "Start self test\n");
83015137daeSFei Qin
83115137daeSFei Qin for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) {
83215137daeSFei Qin if (nfp_self_test[i].is_supported(netdev)) {
83315137daeSFei Qin ret = nfp_self_test[i].func(netdev);
83415137daeSFei Qin if (ret)
83515137daeSFei Qin eth_test->flags |= ETH_TEST_FL_FAILED;
83615137daeSFei Qin data[count++] = ret;
83715137daeSFei Qin }
83815137daeSFei Qin }
83915137daeSFei Qin
84015137daeSFei Qin netdev_info(netdev, "Test end\n");
84115137daeSFei Qin }
84215137daeSFei Qin
nfp_vnic_get_sw_stats_count(struct net_device * netdev)843325945edSJakub Kicinski static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev)
844325945edSJakub Kicinski {
845325945edSJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
846325945edSJakub Kicinski
84751a5e563SJakub Kicinski return NN_RVEC_GATHER_STATS + nn->max_r_vecs * NN_RVEC_PER_Q_STATS +
84851a5e563SJakub Kicinski NN_CTRL_PATH_STATS;
849325945edSJakub Kicinski }
850325945edSJakub Kicinski
nfp_vnic_get_sw_stats_strings(struct net_device * netdev,u8 * data)851325945edSJakub Kicinski static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
8524c352362SJakub Kicinski {
8534c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
8544c352362SJakub Kicinski int i;
8554c352362SJakub Kicinski
856f055a9dfSJakub Kicinski for (i = 0; i < nn->max_r_vecs; i++) {
8576a143a7cSAlexander Duyck ethtool_sprintf(&data, "rvec_%u_rx_pkts", i);
8586a143a7cSAlexander Duyck ethtool_sprintf(&data, "rvec_%u_tx_pkts", i);
8596a143a7cSAlexander Duyck ethtool_sprintf(&data, "rvec_%u_tx_busy", i);
8604c352362SJakub Kicinski }
861634287baSJakub Kicinski
862e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_rx_csum_ok");
863e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_rx_csum_inner_ok");
864e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_rx_csum_complete");
865e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_rx_csum_err");
866e403cfffSjustinstitt@google.com ethtool_puts(&data, "rx_replace_buf_alloc_fail");
867e403cfffSjustinstitt@google.com ethtool_puts(&data, "rx_tls_decrypted_packets");
868e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_tx_csum");
869e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_tx_inner_csum");
870e403cfffSjustinstitt@google.com ethtool_puts(&data, "tx_gather");
871e403cfffSjustinstitt@google.com ethtool_puts(&data, "tx_lso");
872e403cfffSjustinstitt@google.com ethtool_puts(&data, "tx_tls_encrypted_packets");
873e403cfffSjustinstitt@google.com ethtool_puts(&data, "tx_tls_ooo");
874e403cfffSjustinstitt@google.com ethtool_puts(&data, "tx_tls_drop_no_sync_data");
87551a5e563SJakub Kicinski
876e403cfffSjustinstitt@google.com ethtool_puts(&data, "hw_tls_no_space");
877e403cfffSjustinstitt@google.com ethtool_puts(&data, "rx_tls_resync_req_ok");
878e403cfffSjustinstitt@google.com ethtool_puts(&data, "rx_tls_resync_req_ign");
879e403cfffSjustinstitt@google.com ethtool_puts(&data, "rx_tls_resync_sent");
880634287baSJakub Kicinski
881325945edSJakub Kicinski return data;
8824c352362SJakub Kicinski }
883634287baSJakub Kicinski
nfp_vnic_get_sw_stats(struct net_device * netdev,u64 * data)884325945edSJakub Kicinski static u64 *nfp_vnic_get_sw_stats(struct net_device *netdev, u64 *data)
8854c352362SJakub Kicinski {
88618f76191SJakub Kicinski u64 gathered_stats[NN_RVEC_GATHER_STATS] = {};
8874c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
88818f76191SJakub Kicinski u64 tmp[NN_RVEC_GATHER_STATS];
889325945edSJakub Kicinski unsigned int i, j;
8904c352362SJakub Kicinski
891f055a9dfSJakub Kicinski for (i = 0; i < nn->max_r_vecs; i++) {
8924c352362SJakub Kicinski unsigned int start;
8934c352362SJakub Kicinski
8944c352362SJakub Kicinski do {
895068c38adSThomas Gleixner start = u64_stats_fetch_begin(&nn->r_vecs[i].rx_sync);
896c3d64ad4SJakub Kicinski data[0] = nn->r_vecs[i].rx_pkts;
897325945edSJakub Kicinski tmp[0] = nn->r_vecs[i].hw_csum_rx_ok;
898325945edSJakub Kicinski tmp[1] = nn->r_vecs[i].hw_csum_rx_inner_ok;
8990df57e60SJakub Kicinski tmp[2] = nn->r_vecs[i].hw_csum_rx_complete;
9000df57e60SJakub Kicinski tmp[3] = nn->r_vecs[i].hw_csum_rx_error;
9010df57e60SJakub Kicinski tmp[4] = nn->r_vecs[i].rx_replace_buf_alloc_fail;
9025bcb5c7eSDirk van der Merwe tmp[5] = nn->r_vecs[i].hw_tls_rx;
903068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&nn->r_vecs[i].rx_sync, start));
9044c352362SJakub Kicinski
9054c352362SJakub Kicinski do {
906068c38adSThomas Gleixner start = u64_stats_fetch_begin(&nn->r_vecs[i].tx_sync);
907c3d64ad4SJakub Kicinski data[1] = nn->r_vecs[i].tx_pkts;
908c3d64ad4SJakub Kicinski data[2] = nn->r_vecs[i].tx_busy;
9095bcb5c7eSDirk van der Merwe tmp[6] = nn->r_vecs[i].hw_csum_tx;
9105bcb5c7eSDirk van der Merwe tmp[7] = nn->r_vecs[i].hw_csum_tx_inner;
9115bcb5c7eSDirk van der Merwe tmp[8] = nn->r_vecs[i].tx_gather;
9125bcb5c7eSDirk van der Merwe tmp[9] = nn->r_vecs[i].tx_lso;
9135bcb5c7eSDirk van der Merwe tmp[10] = nn->r_vecs[i].hw_tls_tx;
9145bcb5c7eSDirk van der Merwe tmp[11] = nn->r_vecs[i].tls_tx_fallback;
9155bcb5c7eSDirk van der Merwe tmp[12] = nn->r_vecs[i].tls_tx_no_fallback;
916068c38adSThomas Gleixner } while (u64_stats_fetch_retry(&nn->r_vecs[i].tx_sync, start));
9174c352362SJakub Kicinski
91818f76191SJakub Kicinski data += NN_RVEC_PER_Q_STATS;
919c3d64ad4SJakub Kicinski
92018f76191SJakub Kicinski for (j = 0; j < NN_RVEC_GATHER_STATS; j++)
921325945edSJakub Kicinski gathered_stats[j] += tmp[j];
9224c352362SJakub Kicinski }
923325945edSJakub Kicinski
92418f76191SJakub Kicinski for (j = 0; j < NN_RVEC_GATHER_STATS; j++)
925325945edSJakub Kicinski *data++ = gathered_stats[j];
926325945edSJakub Kicinski
92751a5e563SJakub Kicinski *data++ = atomic_read(&nn->ktls_no_space);
9286a35ddc5SJakub Kicinski *data++ = atomic_read(&nn->ktls_rx_resync_req);
9296a35ddc5SJakub Kicinski *data++ = atomic_read(&nn->ktls_rx_resync_ign);
9306a35ddc5SJakub Kicinski *data++ = atomic_read(&nn->ktls_rx_resync_sent);
93151a5e563SJakub Kicinski
932325945edSJakub Kicinski return data;
9334c352362SJakub Kicinski }
934325945edSJakub Kicinski
nfp_vnic_get_hw_stats_count(unsigned int num_vecs)935f055a9dfSJakub Kicinski static unsigned int nfp_vnic_get_hw_stats_count(unsigned int num_vecs)
936325945edSJakub Kicinski {
937f055a9dfSJakub Kicinski return NN_ET_GLOBAL_STATS_LEN + num_vecs * 4;
938325945edSJakub Kicinski }
939325945edSJakub Kicinski
940325945edSJakub Kicinski static u8 *
nfp_vnic_get_hw_stats_strings(u8 * data,unsigned int num_vecs,bool repr)941f055a9dfSJakub Kicinski nfp_vnic_get_hw_stats_strings(u8 *data, unsigned int num_vecs, bool repr)
942325945edSJakub Kicinski {
943899a37adSJakub Kicinski int swap_off, i;
944325945edSJakub Kicinski
945899a37adSJakub Kicinski BUILD_BUG_ON(NN_ET_GLOBAL_STATS_LEN < NN_ET_SWITCH_STATS_LEN * 2);
946899a37adSJakub Kicinski /* If repr is true first add SWITCH_STATS_LEN and then subtract it
947899a37adSJakub Kicinski * effectively swapping the RX and TX statistics (giving us the RX
948899a37adSJakub Kicinski * and TX from perspective of the switch).
949899a37adSJakub Kicinski */
950899a37adSJakub Kicinski swap_off = repr * NN_ET_SWITCH_STATS_LEN;
951899a37adSJakub Kicinski
952899a37adSJakub Kicinski for (i = 0; i < NN_ET_SWITCH_STATS_LEN; i++)
953e403cfffSjustinstitt@google.com ethtool_puts(&data, nfp_net_et_stats[i + swap_off].name);
954899a37adSJakub Kicinski
955899a37adSJakub Kicinski for (i = NN_ET_SWITCH_STATS_LEN; i < NN_ET_SWITCH_STATS_LEN * 2; i++)
956e403cfffSjustinstitt@google.com ethtool_puts(&data, nfp_net_et_stats[i - swap_off].name);
957899a37adSJakub Kicinski
958899a37adSJakub Kicinski for (i = NN_ET_SWITCH_STATS_LEN * 2; i < NN_ET_GLOBAL_STATS_LEN; i++)
959e403cfffSjustinstitt@google.com ethtool_puts(&data, nfp_net_et_stats[i].name);
960325945edSJakub Kicinski
961f055a9dfSJakub Kicinski for (i = 0; i < num_vecs; i++) {
9626a143a7cSAlexander Duyck ethtool_sprintf(&data, "rxq_%u_pkts", i);
9636a143a7cSAlexander Duyck ethtool_sprintf(&data, "rxq_%u_bytes", i);
9646a143a7cSAlexander Duyck ethtool_sprintf(&data, "txq_%u_pkts", i);
9656a143a7cSAlexander Duyck ethtool_sprintf(&data, "txq_%u_bytes", i);
966325945edSJakub Kicinski }
967325945edSJakub Kicinski
968325945edSJakub Kicinski return data;
969325945edSJakub Kicinski }
970325945edSJakub Kicinski
971325945edSJakub Kicinski static u64 *
nfp_vnic_get_hw_stats(u64 * data,u8 __iomem * mem,unsigned int num_vecs)972f055a9dfSJakub Kicinski nfp_vnic_get_hw_stats(u64 *data, u8 __iomem *mem, unsigned int num_vecs)
973325945edSJakub Kicinski {
974325945edSJakub Kicinski unsigned int i;
975325945edSJakub Kicinski
976325945edSJakub Kicinski for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++)
977325945edSJakub Kicinski *data++ = readq(mem + nfp_net_et_stats[i].off);
978325945edSJakub Kicinski
979f055a9dfSJakub Kicinski for (i = 0; i < num_vecs; i++) {
980325945edSJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i));
981325945edSJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i) + 8);
982f055a9dfSJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i));
983f055a9dfSJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i) + 8);
984325945edSJakub Kicinski }
985325945edSJakub Kicinski
986325945edSJakub Kicinski return data;
987325945edSJakub Kicinski }
988325945edSJakub Kicinski
nfp_vnic_get_tlv_stats_count(struct nfp_net * nn)989ca866ee8SJakub Kicinski static unsigned int nfp_vnic_get_tlv_stats_count(struct nfp_net *nn)
990ca866ee8SJakub Kicinski {
991ca866ee8SJakub Kicinski return nn->tlv_caps.vnic_stats_cnt + nn->max_r_vecs * 4;
992ca866ee8SJakub Kicinski }
993ca866ee8SJakub Kicinski
nfp_vnic_get_tlv_stats_strings(struct nfp_net * nn,u8 * data)994ca866ee8SJakub Kicinski static u8 *nfp_vnic_get_tlv_stats_strings(struct nfp_net *nn, u8 *data)
995ca866ee8SJakub Kicinski {
996ca866ee8SJakub Kicinski unsigned int i, id;
997ca866ee8SJakub Kicinski u8 __iomem *mem;
998ca866ee8SJakub Kicinski u64 id_word = 0;
999ca866ee8SJakub Kicinski
1000ca866ee8SJakub Kicinski mem = nn->dp.ctrl_bar + nn->tlv_caps.vnic_stats_off;
1001ca866ee8SJakub Kicinski for (i = 0; i < nn->tlv_caps.vnic_stats_cnt; i++) {
1002ca866ee8SJakub Kicinski if (!(i % 4))
1003ca866ee8SJakub Kicinski id_word = readq(mem + i * 2);
1004ca866ee8SJakub Kicinski
1005ca866ee8SJakub Kicinski id = (u16)id_word;
1006ca866ee8SJakub Kicinski id_word >>= 16;
1007ca866ee8SJakub Kicinski
1008ca866ee8SJakub Kicinski if (id < ARRAY_SIZE(nfp_tlv_stat_names) &&
1009ca866ee8SJakub Kicinski nfp_tlv_stat_names[id][0]) {
1010ca866ee8SJakub Kicinski memcpy(data, nfp_tlv_stat_names[id], ETH_GSTRING_LEN);
1011ca866ee8SJakub Kicinski data += ETH_GSTRING_LEN;
1012ca866ee8SJakub Kicinski } else {
10136a143a7cSAlexander Duyck ethtool_sprintf(&data, "dev_unknown_stat%u", id);
1014ca866ee8SJakub Kicinski }
1015ca866ee8SJakub Kicinski }
1016ca866ee8SJakub Kicinski
1017ca866ee8SJakub Kicinski for (i = 0; i < nn->max_r_vecs; i++) {
10186a143a7cSAlexander Duyck ethtool_sprintf(&data, "rxq_%u_pkts", i);
10196a143a7cSAlexander Duyck ethtool_sprintf(&data, "rxq_%u_bytes", i);
10206a143a7cSAlexander Duyck ethtool_sprintf(&data, "txq_%u_pkts", i);
10216a143a7cSAlexander Duyck ethtool_sprintf(&data, "txq_%u_bytes", i);
1022ca866ee8SJakub Kicinski }
1023ca866ee8SJakub Kicinski
1024ca866ee8SJakub Kicinski return data;
1025ca866ee8SJakub Kicinski }
1026ca866ee8SJakub Kicinski
nfp_vnic_get_tlv_stats(struct nfp_net * nn,u64 * data)1027ca866ee8SJakub Kicinski static u64 *nfp_vnic_get_tlv_stats(struct nfp_net *nn, u64 *data)
1028ca866ee8SJakub Kicinski {
1029ca866ee8SJakub Kicinski u8 __iomem *mem;
1030ca866ee8SJakub Kicinski unsigned int i;
1031ca866ee8SJakub Kicinski
1032ca866ee8SJakub Kicinski mem = nn->dp.ctrl_bar + nn->tlv_caps.vnic_stats_off;
1033ca866ee8SJakub Kicinski mem += roundup(2 * nn->tlv_caps.vnic_stats_cnt, 8);
1034ca866ee8SJakub Kicinski for (i = 0; i < nn->tlv_caps.vnic_stats_cnt; i++)
1035ca866ee8SJakub Kicinski *data++ = readq(mem + i * 8);
1036ca866ee8SJakub Kicinski
1037ca866ee8SJakub Kicinski mem = nn->dp.ctrl_bar;
1038ca866ee8SJakub Kicinski for (i = 0; i < nn->max_r_vecs; i++) {
1039ca866ee8SJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i));
1040ca866ee8SJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_RXR_STATS(i) + 8);
1041ca866ee8SJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i));
1042ca866ee8SJakub Kicinski *data++ = readq(mem + NFP_NET_CFG_TXR_STATS(i) + 8);
1043ca866ee8SJakub Kicinski }
1044ca866ee8SJakub Kicinski
1045ca866ee8SJakub Kicinski return data;
1046ca866ee8SJakub Kicinski }
1047ca866ee8SJakub Kicinski
nfp_mac_get_stats_count(struct net_device * netdev)1048098ce840SJakub Kicinski static unsigned int nfp_mac_get_stats_count(struct net_device *netdev)
1049098ce840SJakub Kicinski {
1050098ce840SJakub Kicinski struct nfp_port *port;
1051098ce840SJakub Kicinski
1052098ce840SJakub Kicinski port = nfp_port_from_netdev(netdev);
1053098ce840SJakub Kicinski if (!__nfp_port_get_eth_port(port) || !port->eth_stats)
1054098ce840SJakub Kicinski return 0;
1055098ce840SJakub Kicinski
1056098ce840SJakub Kicinski return ARRAY_SIZE(nfp_mac_et_stats);
1057098ce840SJakub Kicinski }
1058098ce840SJakub Kicinski
nfp_mac_get_stats_strings(struct net_device * netdev,u8 * data)1059098ce840SJakub Kicinski static u8 *nfp_mac_get_stats_strings(struct net_device *netdev, u8 *data)
1060098ce840SJakub Kicinski {
1061098ce840SJakub Kicinski struct nfp_port *port;
1062098ce840SJakub Kicinski unsigned int i;
1063098ce840SJakub Kicinski
1064098ce840SJakub Kicinski port = nfp_port_from_netdev(netdev);
1065098ce840SJakub Kicinski if (!__nfp_port_get_eth_port(port) || !port->eth_stats)
1066098ce840SJakub Kicinski return data;
1067098ce840SJakub Kicinski
1068098ce840SJakub Kicinski for (i = 0; i < ARRAY_SIZE(nfp_mac_et_stats); i++)
10696a143a7cSAlexander Duyck ethtool_sprintf(&data, "mac.%s", nfp_mac_et_stats[i].name);
1070098ce840SJakub Kicinski
1071098ce840SJakub Kicinski return data;
1072098ce840SJakub Kicinski }
1073098ce840SJakub Kicinski
nfp_mac_get_stats(struct net_device * netdev,u64 * data)1074098ce840SJakub Kicinski static u64 *nfp_mac_get_stats(struct net_device *netdev, u64 *data)
1075098ce840SJakub Kicinski {
1076098ce840SJakub Kicinski struct nfp_port *port;
1077098ce840SJakub Kicinski unsigned int i;
1078098ce840SJakub Kicinski
1079098ce840SJakub Kicinski port = nfp_port_from_netdev(netdev);
1080098ce840SJakub Kicinski if (!__nfp_port_get_eth_port(port) || !port->eth_stats)
1081098ce840SJakub Kicinski return data;
1082098ce840SJakub Kicinski
1083098ce840SJakub Kicinski for (i = 0; i < ARRAY_SIZE(nfp_mac_et_stats); i++)
1084098ce840SJakub Kicinski *data++ = readq(port->eth_stats + nfp_mac_et_stats[i].off);
1085098ce840SJakub Kicinski
1086098ce840SJakub Kicinski return data;
1087098ce840SJakub Kicinski }
1088098ce840SJakub Kicinski
nfp_net_get_strings(struct net_device * netdev,u32 stringset,u8 * data)1089325945edSJakub Kicinski static void nfp_net_get_strings(struct net_device *netdev,
1090325945edSJakub Kicinski u32 stringset, u8 *data)
1091325945edSJakub Kicinski {
1092325945edSJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
1093325945edSJakub Kicinski
1094325945edSJakub Kicinski switch (stringset) {
1095325945edSJakub Kicinski case ETH_SS_STATS:
1096325945edSJakub Kicinski data = nfp_vnic_get_sw_stats_strings(netdev, data);
1097ca866ee8SJakub Kicinski if (!nn->tlv_caps.vnic_stats_off)
1098ca866ee8SJakub Kicinski data = nfp_vnic_get_hw_stats_strings(data,
1099ca866ee8SJakub Kicinski nn->max_r_vecs,
1100899a37adSJakub Kicinski false);
1101ca866ee8SJakub Kicinski else
1102ca866ee8SJakub Kicinski data = nfp_vnic_get_tlv_stats_strings(nn, data);
1103098ce840SJakub Kicinski data = nfp_mac_get_stats_strings(netdev, data);
110421f31bc0SJakub Kicinski data = nfp_app_port_get_stats_strings(nn->port, data);
1105325945edSJakub Kicinski break;
110615137daeSFei Qin case ETH_SS_TEST:
110715137daeSFei Qin nfp_get_self_test_strings(netdev, data);
110815137daeSFei Qin break;
1109325945edSJakub Kicinski }
1110325945edSJakub Kicinski }
1111325945edSJakub Kicinski
1112325945edSJakub Kicinski static void
nfp_net_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)1113325945edSJakub Kicinski nfp_net_get_stats(struct net_device *netdev, struct ethtool_stats *stats,
1114325945edSJakub Kicinski u64 *data)
1115325945edSJakub Kicinski {
1116325945edSJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
1117325945edSJakub Kicinski
1118325945edSJakub Kicinski data = nfp_vnic_get_sw_stats(netdev, data);
1119ca866ee8SJakub Kicinski if (!nn->tlv_caps.vnic_stats_off)
1120ca866ee8SJakub Kicinski data = nfp_vnic_get_hw_stats(data, nn->dp.ctrl_bar,
1121ca866ee8SJakub Kicinski nn->max_r_vecs);
1122ca866ee8SJakub Kicinski else
1123ca866ee8SJakub Kicinski data = nfp_vnic_get_tlv_stats(nn, data);
1124098ce840SJakub Kicinski data = nfp_mac_get_stats(netdev, data);
112521f31bc0SJakub Kicinski data = nfp_app_port_get_stats(nn->port, data);
11264c352362SJakub Kicinski }
11274c352362SJakub Kicinski
nfp_net_get_sset_count(struct net_device * netdev,int sset)11284c352362SJakub Kicinski static int nfp_net_get_sset_count(struct net_device *netdev, int sset)
11294c352362SJakub Kicinski {
11304c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
1131ca866ee8SJakub Kicinski unsigned int cnt;
11324c352362SJakub Kicinski
11334c352362SJakub Kicinski switch (sset) {
11344c352362SJakub Kicinski case ETH_SS_STATS:
1135ca866ee8SJakub Kicinski cnt = nfp_vnic_get_sw_stats_count(netdev);
1136ca866ee8SJakub Kicinski if (!nn->tlv_caps.vnic_stats_off)
1137ca866ee8SJakub Kicinski cnt += nfp_vnic_get_hw_stats_count(nn->max_r_vecs);
1138ca866ee8SJakub Kicinski else
1139ca866ee8SJakub Kicinski cnt += nfp_vnic_get_tlv_stats_count(nn);
1140ca866ee8SJakub Kicinski cnt += nfp_mac_get_stats_count(netdev);
1141ca866ee8SJakub Kicinski cnt += nfp_app_port_get_stats_count(nn->port);
1142ca866ee8SJakub Kicinski return cnt;
114315137daeSFei Qin case ETH_SS_TEST:
114415137daeSFei Qin return nfp_get_self_test_count(netdev);
11454c352362SJakub Kicinski default:
11464c352362SJakub Kicinski return -EOPNOTSUPP;
11474c352362SJakub Kicinski }
11484c352362SJakub Kicinski }
11494c352362SJakub Kicinski
nfp_port_get_strings(struct net_device * netdev,u32 stringset,u8 * data)1150899a37adSJakub Kicinski static void nfp_port_get_strings(struct net_device *netdev,
1151899a37adSJakub Kicinski u32 stringset, u8 *data)
1152899a37adSJakub Kicinski {
1153899a37adSJakub Kicinski struct nfp_port *port = nfp_port_from_netdev(netdev);
1154899a37adSJakub Kicinski
1155899a37adSJakub Kicinski switch (stringset) {
1156899a37adSJakub Kicinski case ETH_SS_STATS:
1157899a37adSJakub Kicinski if (nfp_port_is_vnic(port))
1158f055a9dfSJakub Kicinski data = nfp_vnic_get_hw_stats_strings(data, 0, true);
1159899a37adSJakub Kicinski else
1160899a37adSJakub Kicinski data = nfp_mac_get_stats_strings(netdev, data);
116121f31bc0SJakub Kicinski data = nfp_app_port_get_stats_strings(port, data);
1162899a37adSJakub Kicinski break;
116315137daeSFei Qin case ETH_SS_TEST:
116415137daeSFei Qin nfp_get_self_test_strings(netdev, data);
116515137daeSFei Qin break;
1166899a37adSJakub Kicinski }
1167899a37adSJakub Kicinski }
1168899a37adSJakub Kicinski
1169899a37adSJakub Kicinski static void
nfp_port_get_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)1170899a37adSJakub Kicinski nfp_port_get_stats(struct net_device *netdev, struct ethtool_stats *stats,
1171899a37adSJakub Kicinski u64 *data)
1172899a37adSJakub Kicinski {
1173899a37adSJakub Kicinski struct nfp_port *port = nfp_port_from_netdev(netdev);
1174899a37adSJakub Kicinski
1175899a37adSJakub Kicinski if (nfp_port_is_vnic(port))
1176f055a9dfSJakub Kicinski data = nfp_vnic_get_hw_stats(data, port->vnic, 0);
1177899a37adSJakub Kicinski else
1178899a37adSJakub Kicinski data = nfp_mac_get_stats(netdev, data);
117921f31bc0SJakub Kicinski data = nfp_app_port_get_stats(port, data);
1180899a37adSJakub Kicinski }
1181899a37adSJakub Kicinski
nfp_port_get_sset_count(struct net_device * netdev,int sset)1182899a37adSJakub Kicinski static int nfp_port_get_sset_count(struct net_device *netdev, int sset)
1183899a37adSJakub Kicinski {
1184899a37adSJakub Kicinski struct nfp_port *port = nfp_port_from_netdev(netdev);
1185899a37adSJakub Kicinski unsigned int count;
1186899a37adSJakub Kicinski
1187899a37adSJakub Kicinski switch (sset) {
1188899a37adSJakub Kicinski case ETH_SS_STATS:
1189899a37adSJakub Kicinski if (nfp_port_is_vnic(port))
1190f055a9dfSJakub Kicinski count = nfp_vnic_get_hw_stats_count(0);
1191899a37adSJakub Kicinski else
1192899a37adSJakub Kicinski count = nfp_mac_get_stats_count(netdev);
119321f31bc0SJakub Kicinski count += nfp_app_port_get_stats_count(port);
1194899a37adSJakub Kicinski return count;
119515137daeSFei Qin case ETH_SS_TEST:
119615137daeSFei Qin return nfp_get_self_test_count(netdev);
1197899a37adSJakub Kicinski default:
1198899a37adSJakub Kicinski return -EOPNOTSUPP;
1199899a37adSJakub Kicinski }
1200899a37adSJakub Kicinski }
1201899a37adSJakub Kicinski
nfp_port_fec_ethtool_to_nsp(u32 fec)12020d087093SDirk van der Merwe static int nfp_port_fec_ethtool_to_nsp(u32 fec)
12030d087093SDirk van der Merwe {
12040d087093SDirk van der Merwe switch (fec) {
12050d087093SDirk van der Merwe case ETHTOOL_FEC_AUTO:
12060d087093SDirk van der Merwe return NFP_FEC_AUTO_BIT;
12070d087093SDirk van der Merwe case ETHTOOL_FEC_OFF:
12080d087093SDirk van der Merwe return NFP_FEC_DISABLED_BIT;
12090d087093SDirk van der Merwe case ETHTOOL_FEC_RS:
12100d087093SDirk van der Merwe return NFP_FEC_REED_SOLOMON_BIT;
12110d087093SDirk van der Merwe case ETHTOOL_FEC_BASER:
12120d087093SDirk van der Merwe return NFP_FEC_BASER_BIT;
12130d087093SDirk van der Merwe default:
12140d087093SDirk van der Merwe /* NSP only supports a single mode at a time */
12150d087093SDirk van der Merwe return -EOPNOTSUPP;
12160d087093SDirk van der Merwe }
12170d087093SDirk van der Merwe }
12180d087093SDirk van der Merwe
nfp_port_fec_nsp_to_ethtool(u32 fec)12190d087093SDirk van der Merwe static u32 nfp_port_fec_nsp_to_ethtool(u32 fec)
12200d087093SDirk van der Merwe {
12210d087093SDirk van der Merwe u32 result = 0;
12220d087093SDirk van der Merwe
12230d087093SDirk van der Merwe if (fec & NFP_FEC_AUTO)
12240d087093SDirk van der Merwe result |= ETHTOOL_FEC_AUTO;
12250d087093SDirk van der Merwe if (fec & NFP_FEC_BASER)
12260d087093SDirk van der Merwe result |= ETHTOOL_FEC_BASER;
12270d087093SDirk van der Merwe if (fec & NFP_FEC_REED_SOLOMON)
12280d087093SDirk van der Merwe result |= ETHTOOL_FEC_RS;
12290d087093SDirk van der Merwe if (fec & NFP_FEC_DISABLED)
12300d087093SDirk van der Merwe result |= ETHTOOL_FEC_OFF;
12310d087093SDirk van der Merwe
12320d087093SDirk van der Merwe return result ?: ETHTOOL_FEC_NONE;
12330d087093SDirk van der Merwe }
12340d087093SDirk van der Merwe
12350d087093SDirk van der Merwe static int
nfp_port_get_fecparam(struct net_device * netdev,struct ethtool_fecparam * param)12360d087093SDirk van der Merwe nfp_port_get_fecparam(struct net_device *netdev,
12370d087093SDirk van der Merwe struct ethtool_fecparam *param)
12380d087093SDirk van der Merwe {
12390d087093SDirk van der Merwe struct nfp_eth_table_port *eth_port;
12400d087093SDirk van der Merwe struct nfp_port *port;
12410d087093SDirk van der Merwe
12425f6857e8SJakub Kicinski param->active_fec = ETHTOOL_FEC_NONE;
12435f6857e8SJakub Kicinski param->fec = ETHTOOL_FEC_NONE;
12440d087093SDirk van der Merwe
12450d087093SDirk van der Merwe port = nfp_port_from_netdev(netdev);
12460d087093SDirk van der Merwe eth_port = nfp_port_get_eth_port(port);
12470d087093SDirk van der Merwe if (!eth_port)
12480d087093SDirk van der Merwe return -EOPNOTSUPP;
12490d087093SDirk van der Merwe
12500d087093SDirk van der Merwe if (!nfp_eth_can_support_fec(eth_port))
12510d087093SDirk van der Merwe return 0;
12520d087093SDirk van der Merwe
12530d087093SDirk van der Merwe param->fec = nfp_port_fec_nsp_to_ethtool(eth_port->fec_modes_supported);
1254fc26e70fSYinjun Zhang param->active_fec = nfp_port_fec_nsp_to_ethtool(BIT(eth_port->act_fec));
12550d087093SDirk van der Merwe
12560d087093SDirk van der Merwe return 0;
12570d087093SDirk van der Merwe }
12580d087093SDirk van der Merwe
12590d087093SDirk van der Merwe static int
nfp_port_set_fecparam(struct net_device * netdev,struct ethtool_fecparam * param)12600d087093SDirk van der Merwe nfp_port_set_fecparam(struct net_device *netdev,
12610d087093SDirk van der Merwe struct ethtool_fecparam *param)
12620d087093SDirk van der Merwe {
12630d087093SDirk van der Merwe struct nfp_eth_table_port *eth_port;
12640d087093SDirk van der Merwe struct nfp_port *port;
12650d087093SDirk van der Merwe int err, fec;
12660d087093SDirk van der Merwe
12670d087093SDirk van der Merwe port = nfp_port_from_netdev(netdev);
12680d087093SDirk van der Merwe eth_port = nfp_port_get_eth_port(port);
12690d087093SDirk van der Merwe if (!eth_port)
12700d087093SDirk van der Merwe return -EOPNOTSUPP;
12710d087093SDirk van der Merwe
12720d087093SDirk van der Merwe if (!nfp_eth_can_support_fec(eth_port))
12730d087093SDirk van der Merwe return -EOPNOTSUPP;
12740d087093SDirk van der Merwe
12750d087093SDirk van der Merwe fec = nfp_port_fec_ethtool_to_nsp(param->fec);
12760d087093SDirk van der Merwe if (fec < 0)
12770d087093SDirk van der Merwe return fec;
12780d087093SDirk van der Merwe
12790d087093SDirk van der Merwe err = nfp_eth_set_fec(port->app->cpp, eth_port->index, fec);
12800d087093SDirk van der Merwe if (!err)
12810d087093SDirk van der Merwe /* Only refresh if we did something */
12820d087093SDirk van der Merwe nfp_net_refresh_port_table(port);
12830d087093SDirk van der Merwe
12840d087093SDirk van der Merwe return err < 0 ? err : 0;
12850d087093SDirk van der Merwe }
12860d087093SDirk van der Merwe
12874c352362SJakub Kicinski /* RX network flow classification (RSS, filters, etc)
12884c352362SJakub Kicinski */
ethtool_flow_to_nfp_flag(u32 flow_type)12894c352362SJakub Kicinski static u32 ethtool_flow_to_nfp_flag(u32 flow_type)
12904c352362SJakub Kicinski {
12914c352362SJakub Kicinski static const u32 xlate_ethtool_to_nfp[IPV6_FLOW + 1] = {
12924c352362SJakub Kicinski [TCP_V4_FLOW] = NFP_NET_CFG_RSS_IPV4_TCP,
12934c352362SJakub Kicinski [TCP_V6_FLOW] = NFP_NET_CFG_RSS_IPV6_TCP,
12944c352362SJakub Kicinski [UDP_V4_FLOW] = NFP_NET_CFG_RSS_IPV4_UDP,
12954c352362SJakub Kicinski [UDP_V6_FLOW] = NFP_NET_CFG_RSS_IPV6_UDP,
12964c352362SJakub Kicinski [IPV4_FLOW] = NFP_NET_CFG_RSS_IPV4,
12974c352362SJakub Kicinski [IPV6_FLOW] = NFP_NET_CFG_RSS_IPV6,
12984c352362SJakub Kicinski };
12994c352362SJakub Kicinski
13004c352362SJakub Kicinski if (flow_type >= ARRAY_SIZE(xlate_ethtool_to_nfp))
13014c352362SJakub Kicinski return 0;
13024c352362SJakub Kicinski
13034c352362SJakub Kicinski return xlate_ethtool_to_nfp[flow_type];
13044c352362SJakub Kicinski }
13054c352362SJakub Kicinski
nfp_net_get_rxfh_fields(struct net_device * netdev,struct ethtool_rxfh_fields * cmd)1306*6bfd8cf3SJakub Kicinski static int nfp_net_get_rxfh_fields(struct net_device *netdev,
1307*6bfd8cf3SJakub Kicinski struct ethtool_rxfh_fields *cmd)
13084c352362SJakub Kicinski {
1309*6bfd8cf3SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
13104c352362SJakub Kicinski u32 nfp_rss_flag;
13114c352362SJakub Kicinski
13124c352362SJakub Kicinski cmd->data = 0;
13134c352362SJakub Kicinski
1314611bdd49SEdwin Peer if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
13154c352362SJakub Kicinski return -EOPNOTSUPP;
13164c352362SJakub Kicinski
13174c352362SJakub Kicinski nfp_rss_flag = ethtool_flow_to_nfp_flag(cmd->flow_type);
13184c352362SJakub Kicinski if (!nfp_rss_flag)
13194c352362SJakub Kicinski return -EINVAL;
13204c352362SJakub Kicinski
13214c352362SJakub Kicinski cmd->data |= RXH_IP_SRC | RXH_IP_DST;
13224c352362SJakub Kicinski if (nn->rss_cfg & nfp_rss_flag)
13234c352362SJakub Kicinski cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
13244c352362SJakub Kicinski
13254c352362SJakub Kicinski return 0;
13264c352362SJakub Kicinski }
13274c352362SJakub Kicinski
13289eb03bb1SYinjun Zhang #define NFP_FS_MAX_ENTRY 1024
13299eb03bb1SYinjun Zhang
nfp_net_fs_to_ethtool(struct nfp_fs_entry * entry,struct ethtool_rxnfc * cmd)13309eb03bb1SYinjun Zhang static int nfp_net_fs_to_ethtool(struct nfp_fs_entry *entry, struct ethtool_rxnfc *cmd)
13319eb03bb1SYinjun Zhang {
13329eb03bb1SYinjun Zhang struct ethtool_rx_flow_spec *fs = &cmd->fs;
13339eb03bb1SYinjun Zhang unsigned int i;
13349eb03bb1SYinjun Zhang
13359eb03bb1SYinjun Zhang switch (entry->flow_type & ~FLOW_RSS) {
13369eb03bb1SYinjun Zhang case TCP_V4_FLOW:
13379eb03bb1SYinjun Zhang case UDP_V4_FLOW:
13389eb03bb1SYinjun Zhang case SCTP_V4_FLOW:
13399eb03bb1SYinjun Zhang fs->h_u.tcp_ip4_spec.ip4src = entry->key.sip4;
13409eb03bb1SYinjun Zhang fs->h_u.tcp_ip4_spec.ip4dst = entry->key.dip4;
13419eb03bb1SYinjun Zhang fs->h_u.tcp_ip4_spec.psrc = entry->key.sport;
13429eb03bb1SYinjun Zhang fs->h_u.tcp_ip4_spec.pdst = entry->key.dport;
13439eb03bb1SYinjun Zhang fs->m_u.tcp_ip4_spec.ip4src = entry->msk.sip4;
13449eb03bb1SYinjun Zhang fs->m_u.tcp_ip4_spec.ip4dst = entry->msk.dip4;
13459eb03bb1SYinjun Zhang fs->m_u.tcp_ip4_spec.psrc = entry->msk.sport;
13469eb03bb1SYinjun Zhang fs->m_u.tcp_ip4_spec.pdst = entry->msk.dport;
13479eb03bb1SYinjun Zhang break;
13489eb03bb1SYinjun Zhang case TCP_V6_FLOW:
13499eb03bb1SYinjun Zhang case UDP_V6_FLOW:
13509eb03bb1SYinjun Zhang case SCTP_V6_FLOW:
13519eb03bb1SYinjun Zhang for (i = 0; i < 4; i++) {
13529eb03bb1SYinjun Zhang fs->h_u.tcp_ip6_spec.ip6src[i] = entry->key.sip6[i];
13539eb03bb1SYinjun Zhang fs->h_u.tcp_ip6_spec.ip6dst[i] = entry->key.dip6[i];
13549eb03bb1SYinjun Zhang fs->m_u.tcp_ip6_spec.ip6src[i] = entry->msk.sip6[i];
13559eb03bb1SYinjun Zhang fs->m_u.tcp_ip6_spec.ip6dst[i] = entry->msk.dip6[i];
13569eb03bb1SYinjun Zhang }
13579eb03bb1SYinjun Zhang fs->h_u.tcp_ip6_spec.psrc = entry->key.sport;
13589eb03bb1SYinjun Zhang fs->h_u.tcp_ip6_spec.pdst = entry->key.dport;
13599eb03bb1SYinjun Zhang fs->m_u.tcp_ip6_spec.psrc = entry->msk.sport;
13609eb03bb1SYinjun Zhang fs->m_u.tcp_ip6_spec.pdst = entry->msk.dport;
13619eb03bb1SYinjun Zhang break;
13629eb03bb1SYinjun Zhang case IPV4_USER_FLOW:
13639eb03bb1SYinjun Zhang fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
13649eb03bb1SYinjun Zhang fs->h_u.usr_ip4_spec.ip4src = entry->key.sip4;
13659eb03bb1SYinjun Zhang fs->h_u.usr_ip4_spec.ip4dst = entry->key.dip4;
13669eb03bb1SYinjun Zhang fs->h_u.usr_ip4_spec.proto = entry->key.l4_proto;
13679eb03bb1SYinjun Zhang fs->m_u.usr_ip4_spec.ip4src = entry->msk.sip4;
13689eb03bb1SYinjun Zhang fs->m_u.usr_ip4_spec.ip4dst = entry->msk.dip4;
13699eb03bb1SYinjun Zhang fs->m_u.usr_ip4_spec.proto = entry->msk.l4_proto;
13709eb03bb1SYinjun Zhang break;
13719eb03bb1SYinjun Zhang case IPV6_USER_FLOW:
13729eb03bb1SYinjun Zhang for (i = 0; i < 4; i++) {
13739eb03bb1SYinjun Zhang fs->h_u.usr_ip6_spec.ip6src[i] = entry->key.sip6[i];
13749eb03bb1SYinjun Zhang fs->h_u.usr_ip6_spec.ip6dst[i] = entry->key.dip6[i];
13759eb03bb1SYinjun Zhang fs->m_u.usr_ip6_spec.ip6src[i] = entry->msk.sip6[i];
13769eb03bb1SYinjun Zhang fs->m_u.usr_ip6_spec.ip6dst[i] = entry->msk.dip6[i];
13779eb03bb1SYinjun Zhang }
13789eb03bb1SYinjun Zhang fs->h_u.usr_ip6_spec.l4_proto = entry->key.l4_proto;
13799eb03bb1SYinjun Zhang fs->m_u.usr_ip6_spec.l4_proto = entry->msk.l4_proto;
13809eb03bb1SYinjun Zhang break;
13819eb03bb1SYinjun Zhang case ETHER_FLOW:
13829eb03bb1SYinjun Zhang fs->h_u.ether_spec.h_proto = entry->key.l3_proto;
13839eb03bb1SYinjun Zhang fs->m_u.ether_spec.h_proto = entry->msk.l3_proto;
13849eb03bb1SYinjun Zhang break;
13859eb03bb1SYinjun Zhang default:
13869eb03bb1SYinjun Zhang return -EINVAL;
13879eb03bb1SYinjun Zhang }
13889eb03bb1SYinjun Zhang
13899eb03bb1SYinjun Zhang fs->flow_type = entry->flow_type;
13909eb03bb1SYinjun Zhang fs->ring_cookie = entry->action;
13919eb03bb1SYinjun Zhang
13929eb03bb1SYinjun Zhang if (fs->flow_type & FLOW_RSS) {
13939eb03bb1SYinjun Zhang /* Only rss_context of 0 is supported. */
13949eb03bb1SYinjun Zhang cmd->rss_context = 0;
13959eb03bb1SYinjun Zhang /* RSS is used, mask the ring. */
13969eb03bb1SYinjun Zhang fs->ring_cookie |= ETHTOOL_RX_FLOW_SPEC_RING;
13979eb03bb1SYinjun Zhang }
13989eb03bb1SYinjun Zhang
13999eb03bb1SYinjun Zhang return 0;
14009eb03bb1SYinjun Zhang }
14019eb03bb1SYinjun Zhang
nfp_net_get_fs_rule(struct nfp_net * nn,struct ethtool_rxnfc * cmd)14029eb03bb1SYinjun Zhang static int nfp_net_get_fs_rule(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
14039eb03bb1SYinjun Zhang {
14049eb03bb1SYinjun Zhang struct nfp_fs_entry *entry;
14059eb03bb1SYinjun Zhang
14069eb03bb1SYinjun Zhang if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
14079eb03bb1SYinjun Zhang return -EOPNOTSUPP;
14089eb03bb1SYinjun Zhang
14099eb03bb1SYinjun Zhang if (cmd->fs.location >= NFP_FS_MAX_ENTRY)
14109eb03bb1SYinjun Zhang return -EINVAL;
14119eb03bb1SYinjun Zhang
14129eb03bb1SYinjun Zhang list_for_each_entry(entry, &nn->fs.list, node) {
14139eb03bb1SYinjun Zhang if (entry->loc == cmd->fs.location)
14149eb03bb1SYinjun Zhang return nfp_net_fs_to_ethtool(entry, cmd);
14159eb03bb1SYinjun Zhang
14169eb03bb1SYinjun Zhang if (entry->loc > cmd->fs.location)
14179eb03bb1SYinjun Zhang /* no need to continue */
14189eb03bb1SYinjun Zhang return -ENOENT;
14199eb03bb1SYinjun Zhang }
14209eb03bb1SYinjun Zhang
14219eb03bb1SYinjun Zhang return -ENOENT;
14229eb03bb1SYinjun Zhang }
14239eb03bb1SYinjun Zhang
nfp_net_get_fs_loc(struct nfp_net * nn,u32 * rule_locs)14249eb03bb1SYinjun Zhang static int nfp_net_get_fs_loc(struct nfp_net *nn, u32 *rule_locs)
14259eb03bb1SYinjun Zhang {
14269eb03bb1SYinjun Zhang struct nfp_fs_entry *entry;
14279eb03bb1SYinjun Zhang u32 count = 0;
14289eb03bb1SYinjun Zhang
14299eb03bb1SYinjun Zhang if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
14309eb03bb1SYinjun Zhang return -EOPNOTSUPP;
14319eb03bb1SYinjun Zhang
14329eb03bb1SYinjun Zhang list_for_each_entry(entry, &nn->fs.list, node)
14339eb03bb1SYinjun Zhang rule_locs[count++] = entry->loc;
14349eb03bb1SYinjun Zhang
14359eb03bb1SYinjun Zhang return 0;
14369eb03bb1SYinjun Zhang }
14379eb03bb1SYinjun Zhang
nfp_net_get_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * cmd,u32 * rule_locs)14384c352362SJakub Kicinski static int nfp_net_get_rxnfc(struct net_device *netdev,
14394c352362SJakub Kicinski struct ethtool_rxnfc *cmd, u32 *rule_locs)
14404c352362SJakub Kicinski {
14414c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
14424c352362SJakub Kicinski
14434c352362SJakub Kicinski switch (cmd->cmd) {
14444c352362SJakub Kicinski case ETHTOOL_GRXRINGS:
144579c12a75SJakub Kicinski cmd->data = nn->dp.num_rx_rings;
14464c352362SJakub Kicinski return 0;
14479eb03bb1SYinjun Zhang case ETHTOOL_GRXCLSRLCNT:
14489eb03bb1SYinjun Zhang cmd->rule_cnt = nn->fs.count;
14499eb03bb1SYinjun Zhang return 0;
14509eb03bb1SYinjun Zhang case ETHTOOL_GRXCLSRULE:
14519eb03bb1SYinjun Zhang return nfp_net_get_fs_rule(nn, cmd);
14529eb03bb1SYinjun Zhang case ETHTOOL_GRXCLSRLALL:
14539eb03bb1SYinjun Zhang cmd->data = NFP_FS_MAX_ENTRY;
14549eb03bb1SYinjun Zhang return nfp_net_get_fs_loc(nn, rule_locs);
14554c352362SJakub Kicinski default:
14564c352362SJakub Kicinski return -EOPNOTSUPP;
14574c352362SJakub Kicinski }
14584c352362SJakub Kicinski }
14594c352362SJakub Kicinski
nfp_net_set_rxfh_fields(struct net_device * netdev,const struct ethtool_rxfh_fields * nfc,struct netlink_ext_ack * extack)1460*6bfd8cf3SJakub Kicinski static int nfp_net_set_rxfh_fields(struct net_device *netdev,
1461*6bfd8cf3SJakub Kicinski const struct ethtool_rxfh_fields *nfc,
1462*6bfd8cf3SJakub Kicinski struct netlink_ext_ack *extack)
14634c352362SJakub Kicinski {
1464*6bfd8cf3SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
14654c352362SJakub Kicinski u32 new_rss_cfg = nn->rss_cfg;
14664c352362SJakub Kicinski u32 nfp_rss_flag;
14674c352362SJakub Kicinski int err;
14684c352362SJakub Kicinski
1469611bdd49SEdwin Peer if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
14704c352362SJakub Kicinski return -EOPNOTSUPP;
14714c352362SJakub Kicinski
14724c352362SJakub Kicinski /* RSS only supports IP SA/DA and L4 src/dst ports */
14734c352362SJakub Kicinski if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
14744c352362SJakub Kicinski RXH_L4_B_0_1 | RXH_L4_B_2_3))
14754c352362SJakub Kicinski return -EINVAL;
14764c352362SJakub Kicinski
14774c352362SJakub Kicinski /* We need at least the IP SA/DA fields for hashing */
14784c352362SJakub Kicinski if (!(nfc->data & RXH_IP_SRC) ||
14794c352362SJakub Kicinski !(nfc->data & RXH_IP_DST))
14804c352362SJakub Kicinski return -EINVAL;
14814c352362SJakub Kicinski
14824c352362SJakub Kicinski nfp_rss_flag = ethtool_flow_to_nfp_flag(nfc->flow_type);
14834c352362SJakub Kicinski if (!nfp_rss_flag)
14844c352362SJakub Kicinski return -EINVAL;
14854c352362SJakub Kicinski
14864c352362SJakub Kicinski switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
14874c352362SJakub Kicinski case 0:
14884c352362SJakub Kicinski new_rss_cfg &= ~nfp_rss_flag;
14894c352362SJakub Kicinski break;
14904c352362SJakub Kicinski case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
14914c352362SJakub Kicinski new_rss_cfg |= nfp_rss_flag;
14924c352362SJakub Kicinski break;
14934c352362SJakub Kicinski default:
14944c352362SJakub Kicinski return -EINVAL;
14954c352362SJakub Kicinski }
14964c352362SJakub Kicinski
14979ff304bfSJakub Kicinski new_rss_cfg |= FIELD_PREP(NFP_NET_CFG_RSS_HFUNC, nn->rss_hfunc);
14984c352362SJakub Kicinski new_rss_cfg |= NFP_NET_CFG_RSS_MASK;
14994c352362SJakub Kicinski
15004c352362SJakub Kicinski if (new_rss_cfg == nn->rss_cfg)
15014c352362SJakub Kicinski return 0;
15024c352362SJakub Kicinski
1503d2b84397SJakub Kicinski writel(new_rss_cfg, nn->dp.ctrl_bar + NFP_NET_CFG_RSS_CTRL);
15044c352362SJakub Kicinski err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_RSS);
15054c352362SJakub Kicinski if (err)
15064c352362SJakub Kicinski return err;
15074c352362SJakub Kicinski
15084c352362SJakub Kicinski nn->rss_cfg = new_rss_cfg;
15094c352362SJakub Kicinski
15104c352362SJakub Kicinski nn_dbg(nn, "Changed RSS config to 0x%x\n", nn->rss_cfg);
15114c352362SJakub Kicinski return 0;
15124c352362SJakub Kicinski }
15134c352362SJakub Kicinski
nfp_net_fs_from_ethtool(struct nfp_fs_entry * entry,struct ethtool_rx_flow_spec * fs)15149eb03bb1SYinjun Zhang static int nfp_net_fs_from_ethtool(struct nfp_fs_entry *entry, struct ethtool_rx_flow_spec *fs)
15159eb03bb1SYinjun Zhang {
15169eb03bb1SYinjun Zhang unsigned int i;
15179eb03bb1SYinjun Zhang
15189eb03bb1SYinjun Zhang /* FLOW_EXT/FLOW_MAC_EXT is not supported. */
15199eb03bb1SYinjun Zhang switch (fs->flow_type & ~FLOW_RSS) {
15209eb03bb1SYinjun Zhang case TCP_V4_FLOW:
15219eb03bb1SYinjun Zhang case UDP_V4_FLOW:
15229eb03bb1SYinjun Zhang case SCTP_V4_FLOW:
15239eb03bb1SYinjun Zhang entry->msk.sip4 = fs->m_u.tcp_ip4_spec.ip4src;
15249eb03bb1SYinjun Zhang entry->msk.dip4 = fs->m_u.tcp_ip4_spec.ip4dst;
15259eb03bb1SYinjun Zhang entry->msk.sport = fs->m_u.tcp_ip4_spec.psrc;
15269eb03bb1SYinjun Zhang entry->msk.dport = fs->m_u.tcp_ip4_spec.pdst;
15279eb03bb1SYinjun Zhang entry->key.sip4 = fs->h_u.tcp_ip4_spec.ip4src & entry->msk.sip4;
15289eb03bb1SYinjun Zhang entry->key.dip4 = fs->h_u.tcp_ip4_spec.ip4dst & entry->msk.dip4;
15299eb03bb1SYinjun Zhang entry->key.sport = fs->h_u.tcp_ip4_spec.psrc & entry->msk.sport;
15309eb03bb1SYinjun Zhang entry->key.dport = fs->h_u.tcp_ip4_spec.pdst & entry->msk.dport;
15319eb03bb1SYinjun Zhang break;
15329eb03bb1SYinjun Zhang case TCP_V6_FLOW:
15339eb03bb1SYinjun Zhang case UDP_V6_FLOW:
15349eb03bb1SYinjun Zhang case SCTP_V6_FLOW:
15359eb03bb1SYinjun Zhang for (i = 0; i < 4; i++) {
15369eb03bb1SYinjun Zhang entry->msk.sip6[i] = fs->m_u.tcp_ip6_spec.ip6src[i];
15379eb03bb1SYinjun Zhang entry->msk.dip6[i] = fs->m_u.tcp_ip6_spec.ip6dst[i];
15389eb03bb1SYinjun Zhang entry->key.sip6[i] = fs->h_u.tcp_ip6_spec.ip6src[i] & entry->msk.sip6[i];
15399eb03bb1SYinjun Zhang entry->key.dip6[i] = fs->h_u.tcp_ip6_spec.ip6dst[i] & entry->msk.dip6[i];
15409eb03bb1SYinjun Zhang }
15419eb03bb1SYinjun Zhang entry->msk.sport = fs->m_u.tcp_ip6_spec.psrc;
15429eb03bb1SYinjun Zhang entry->msk.dport = fs->m_u.tcp_ip6_spec.pdst;
15439eb03bb1SYinjun Zhang entry->key.sport = fs->h_u.tcp_ip6_spec.psrc & entry->msk.sport;
15449eb03bb1SYinjun Zhang entry->key.dport = fs->h_u.tcp_ip6_spec.pdst & entry->msk.dport;
15459eb03bb1SYinjun Zhang break;
15469eb03bb1SYinjun Zhang case IPV4_USER_FLOW:
15479eb03bb1SYinjun Zhang entry->msk.sip4 = fs->m_u.usr_ip4_spec.ip4src;
15489eb03bb1SYinjun Zhang entry->msk.dip4 = fs->m_u.usr_ip4_spec.ip4dst;
15499eb03bb1SYinjun Zhang entry->msk.l4_proto = fs->m_u.usr_ip4_spec.proto;
15509eb03bb1SYinjun Zhang entry->key.sip4 = fs->h_u.usr_ip4_spec.ip4src & entry->msk.sip4;
15519eb03bb1SYinjun Zhang entry->key.dip4 = fs->h_u.usr_ip4_spec.ip4dst & entry->msk.dip4;
15529eb03bb1SYinjun Zhang entry->key.l4_proto = fs->h_u.usr_ip4_spec.proto & entry->msk.l4_proto;
15539eb03bb1SYinjun Zhang break;
15549eb03bb1SYinjun Zhang case IPV6_USER_FLOW:
15559eb03bb1SYinjun Zhang for (i = 0; i < 4; i++) {
15569eb03bb1SYinjun Zhang entry->msk.sip6[i] = fs->m_u.usr_ip6_spec.ip6src[i];
15579eb03bb1SYinjun Zhang entry->msk.dip6[i] = fs->m_u.usr_ip6_spec.ip6dst[i];
15589eb03bb1SYinjun Zhang entry->key.sip6[i] = fs->h_u.usr_ip6_spec.ip6src[i] & entry->msk.sip6[i];
15599eb03bb1SYinjun Zhang entry->key.dip6[i] = fs->h_u.usr_ip6_spec.ip6dst[i] & entry->msk.dip6[i];
15609eb03bb1SYinjun Zhang }
15619eb03bb1SYinjun Zhang entry->msk.l4_proto = fs->m_u.usr_ip6_spec.l4_proto;
15629eb03bb1SYinjun Zhang entry->key.l4_proto = fs->h_u.usr_ip6_spec.l4_proto & entry->msk.l4_proto;
15639eb03bb1SYinjun Zhang break;
15649eb03bb1SYinjun Zhang case ETHER_FLOW:
15659eb03bb1SYinjun Zhang entry->msk.l3_proto = fs->m_u.ether_spec.h_proto;
15669eb03bb1SYinjun Zhang entry->key.l3_proto = fs->h_u.ether_spec.h_proto & entry->msk.l3_proto;
15679eb03bb1SYinjun Zhang break;
15689eb03bb1SYinjun Zhang default:
15699eb03bb1SYinjun Zhang return -EINVAL;
15709eb03bb1SYinjun Zhang }
15719eb03bb1SYinjun Zhang
15729eb03bb1SYinjun Zhang switch (fs->flow_type & ~FLOW_RSS) {
15739eb03bb1SYinjun Zhang case TCP_V4_FLOW:
15749eb03bb1SYinjun Zhang case TCP_V6_FLOW:
15759eb03bb1SYinjun Zhang entry->key.l4_proto = IPPROTO_TCP;
15769eb03bb1SYinjun Zhang entry->msk.l4_proto = 0xff;
15779eb03bb1SYinjun Zhang break;
15789eb03bb1SYinjun Zhang case UDP_V4_FLOW:
15799eb03bb1SYinjun Zhang case UDP_V6_FLOW:
15809eb03bb1SYinjun Zhang entry->key.l4_proto = IPPROTO_UDP;
15819eb03bb1SYinjun Zhang entry->msk.l4_proto = 0xff;
15829eb03bb1SYinjun Zhang break;
15839eb03bb1SYinjun Zhang case SCTP_V4_FLOW:
15849eb03bb1SYinjun Zhang case SCTP_V6_FLOW:
15859eb03bb1SYinjun Zhang entry->key.l4_proto = IPPROTO_SCTP;
15869eb03bb1SYinjun Zhang entry->msk.l4_proto = 0xff;
15879eb03bb1SYinjun Zhang break;
15889eb03bb1SYinjun Zhang }
15899eb03bb1SYinjun Zhang
15909eb03bb1SYinjun Zhang entry->flow_type = fs->flow_type;
15919eb03bb1SYinjun Zhang entry->action = fs->ring_cookie;
15929eb03bb1SYinjun Zhang entry->loc = fs->location;
15939eb03bb1SYinjun Zhang
15949eb03bb1SYinjun Zhang return 0;
15959eb03bb1SYinjun Zhang }
15969eb03bb1SYinjun Zhang
nfp_net_fs_check_existing(struct nfp_net * nn,struct nfp_fs_entry * new)15979eb03bb1SYinjun Zhang static int nfp_net_fs_check_existing(struct nfp_net *nn, struct nfp_fs_entry *new)
15989eb03bb1SYinjun Zhang {
15999eb03bb1SYinjun Zhang struct nfp_fs_entry *entry;
16009eb03bb1SYinjun Zhang
16019eb03bb1SYinjun Zhang list_for_each_entry(entry, &nn->fs.list, node) {
16029eb03bb1SYinjun Zhang if (new->loc != entry->loc &&
16039eb03bb1SYinjun Zhang !((new->flow_type ^ entry->flow_type) & ~FLOW_RSS) &&
16049eb03bb1SYinjun Zhang !memcmp(&new->key, &entry->key, sizeof(new->key)) &&
16059eb03bb1SYinjun Zhang !memcmp(&new->msk, &entry->msk, sizeof(new->msk)))
16069eb03bb1SYinjun Zhang return entry->loc;
16079eb03bb1SYinjun Zhang }
16089eb03bb1SYinjun Zhang
16099eb03bb1SYinjun Zhang /* -1 means no duplicates */
16109eb03bb1SYinjun Zhang return -1;
16119eb03bb1SYinjun Zhang }
16129eb03bb1SYinjun Zhang
nfp_net_fs_add(struct nfp_net * nn,struct ethtool_rxnfc * cmd)16139eb03bb1SYinjun Zhang static int nfp_net_fs_add(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
16149eb03bb1SYinjun Zhang {
16159eb03bb1SYinjun Zhang struct ethtool_rx_flow_spec *fs = &cmd->fs;
16169eb03bb1SYinjun Zhang struct nfp_fs_entry *new, *entry;
16179eb03bb1SYinjun Zhang bool unsupp_mask;
16189eb03bb1SYinjun Zhang int err, id;
16199eb03bb1SYinjun Zhang
16209eb03bb1SYinjun Zhang if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
16219eb03bb1SYinjun Zhang return -EOPNOTSUPP;
16229eb03bb1SYinjun Zhang
16239eb03bb1SYinjun Zhang /* Only default RSS context(0) is supported. */
16249eb03bb1SYinjun Zhang if ((fs->flow_type & FLOW_RSS) && cmd->rss_context)
16259eb03bb1SYinjun Zhang return -EOPNOTSUPP;
16269eb03bb1SYinjun Zhang
16279eb03bb1SYinjun Zhang if (fs->location >= NFP_FS_MAX_ENTRY)
16289eb03bb1SYinjun Zhang return -EINVAL;
16299eb03bb1SYinjun Zhang
16309eb03bb1SYinjun Zhang if (fs->ring_cookie != RX_CLS_FLOW_DISC &&
16319eb03bb1SYinjun Zhang fs->ring_cookie >= nn->dp.num_rx_rings)
16329eb03bb1SYinjun Zhang return -EINVAL;
16339eb03bb1SYinjun Zhang
16349eb03bb1SYinjun Zhang /* FLOW_EXT/FLOW_MAC_EXT is not supported. */
16359eb03bb1SYinjun Zhang switch (fs->flow_type & ~FLOW_RSS) {
16369eb03bb1SYinjun Zhang case TCP_V4_FLOW:
16379eb03bb1SYinjun Zhang case UDP_V4_FLOW:
16389eb03bb1SYinjun Zhang case SCTP_V4_FLOW:
16399eb03bb1SYinjun Zhang unsupp_mask = !!fs->m_u.tcp_ip4_spec.tos;
16409eb03bb1SYinjun Zhang break;
16419eb03bb1SYinjun Zhang case TCP_V6_FLOW:
16429eb03bb1SYinjun Zhang case UDP_V6_FLOW:
16439eb03bb1SYinjun Zhang case SCTP_V6_FLOW:
16449eb03bb1SYinjun Zhang unsupp_mask = !!fs->m_u.tcp_ip6_spec.tclass;
16459eb03bb1SYinjun Zhang break;
16469eb03bb1SYinjun Zhang case IPV4_USER_FLOW:
16479eb03bb1SYinjun Zhang unsupp_mask = !!fs->m_u.usr_ip4_spec.l4_4_bytes ||
16489eb03bb1SYinjun Zhang !!fs->m_u.usr_ip4_spec.tos ||
16499eb03bb1SYinjun Zhang !!fs->m_u.usr_ip4_spec.ip_ver;
16509eb03bb1SYinjun Zhang /* ip_ver must be ETH_RX_NFC_IP4. */
16519eb03bb1SYinjun Zhang unsupp_mask |= fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4;
16529eb03bb1SYinjun Zhang break;
16539eb03bb1SYinjun Zhang case IPV6_USER_FLOW:
16549eb03bb1SYinjun Zhang unsupp_mask = !!fs->m_u.usr_ip6_spec.l4_4_bytes ||
16559eb03bb1SYinjun Zhang !!fs->m_u.usr_ip6_spec.tclass;
16569eb03bb1SYinjun Zhang break;
16579eb03bb1SYinjun Zhang case ETHER_FLOW:
16589eb03bb1SYinjun Zhang if (fs->h_u.ether_spec.h_proto == htons(ETH_P_IP) ||
16599eb03bb1SYinjun Zhang fs->h_u.ether_spec.h_proto == htons(ETH_P_IPV6)) {
16609eb03bb1SYinjun Zhang nn_err(nn, "Please use ip4/ip6 flow type instead.\n");
16619eb03bb1SYinjun Zhang return -EOPNOTSUPP;
16629eb03bb1SYinjun Zhang }
16639eb03bb1SYinjun Zhang /* Only unmasked ethtype is supported. */
16649eb03bb1SYinjun Zhang unsupp_mask = !is_zero_ether_addr(fs->m_u.ether_spec.h_dest) ||
16659eb03bb1SYinjun Zhang !is_zero_ether_addr(fs->m_u.ether_spec.h_source) ||
16669eb03bb1SYinjun Zhang (fs->m_u.ether_spec.h_proto != htons(0xffff));
16679eb03bb1SYinjun Zhang break;
16689eb03bb1SYinjun Zhang default:
16699eb03bb1SYinjun Zhang return -EOPNOTSUPP;
16709eb03bb1SYinjun Zhang }
16719eb03bb1SYinjun Zhang
16729eb03bb1SYinjun Zhang if (unsupp_mask)
16739eb03bb1SYinjun Zhang return -EOPNOTSUPP;
16749eb03bb1SYinjun Zhang
16759eb03bb1SYinjun Zhang new = kzalloc(sizeof(*new), GFP_KERNEL);
16769eb03bb1SYinjun Zhang if (!new)
16779eb03bb1SYinjun Zhang return -ENOMEM;
16789eb03bb1SYinjun Zhang
16799eb03bb1SYinjun Zhang nfp_net_fs_from_ethtool(new, fs);
16809eb03bb1SYinjun Zhang
16819eb03bb1SYinjun Zhang id = nfp_net_fs_check_existing(nn, new);
16829eb03bb1SYinjun Zhang if (id >= 0) {
16839eb03bb1SYinjun Zhang nn_err(nn, "Identical rule is existing in %d.\n", id);
16849eb03bb1SYinjun Zhang err = -EINVAL;
16859eb03bb1SYinjun Zhang goto err;
16869eb03bb1SYinjun Zhang }
16879eb03bb1SYinjun Zhang
16889eb03bb1SYinjun Zhang /* Insert to list in ascending order of location. */
16899eb03bb1SYinjun Zhang list_for_each_entry(entry, &nn->fs.list, node) {
16909eb03bb1SYinjun Zhang if (entry->loc == fs->location) {
16919eb03bb1SYinjun Zhang err = nfp_net_fs_del_hw(nn, entry);
16929eb03bb1SYinjun Zhang if (err)
16939eb03bb1SYinjun Zhang goto err;
16949eb03bb1SYinjun Zhang
16959eb03bb1SYinjun Zhang nn->fs.count--;
16969eb03bb1SYinjun Zhang err = nfp_net_fs_add_hw(nn, new);
16979eb03bb1SYinjun Zhang if (err)
16989eb03bb1SYinjun Zhang goto err;
16999eb03bb1SYinjun Zhang
17009eb03bb1SYinjun Zhang nn->fs.count++;
17019eb03bb1SYinjun Zhang list_replace(&entry->node, &new->node);
17029eb03bb1SYinjun Zhang kfree(entry);
17039eb03bb1SYinjun Zhang
17049eb03bb1SYinjun Zhang return 0;
17059eb03bb1SYinjun Zhang }
17069eb03bb1SYinjun Zhang
17079eb03bb1SYinjun Zhang if (entry->loc > fs->location)
17089eb03bb1SYinjun Zhang break;
17099eb03bb1SYinjun Zhang }
17109eb03bb1SYinjun Zhang
17119eb03bb1SYinjun Zhang if (nn->fs.count == NFP_FS_MAX_ENTRY) {
17129eb03bb1SYinjun Zhang err = -ENOSPC;
17139eb03bb1SYinjun Zhang goto err;
17149eb03bb1SYinjun Zhang }
17159eb03bb1SYinjun Zhang
17169eb03bb1SYinjun Zhang err = nfp_net_fs_add_hw(nn, new);
17179eb03bb1SYinjun Zhang if (err)
17189eb03bb1SYinjun Zhang goto err;
17199eb03bb1SYinjun Zhang
17209eb03bb1SYinjun Zhang list_add_tail(&new->node, &entry->node);
17219eb03bb1SYinjun Zhang nn->fs.count++;
17229eb03bb1SYinjun Zhang
17239eb03bb1SYinjun Zhang return 0;
17249eb03bb1SYinjun Zhang
17259eb03bb1SYinjun Zhang err:
17269eb03bb1SYinjun Zhang kfree(new);
17279eb03bb1SYinjun Zhang return err;
17289eb03bb1SYinjun Zhang }
17299eb03bb1SYinjun Zhang
nfp_net_fs_del(struct nfp_net * nn,struct ethtool_rxnfc * cmd)17309eb03bb1SYinjun Zhang static int nfp_net_fs_del(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
17319eb03bb1SYinjun Zhang {
17329eb03bb1SYinjun Zhang struct nfp_fs_entry *entry;
17339eb03bb1SYinjun Zhang int err;
17349eb03bb1SYinjun Zhang
17359eb03bb1SYinjun Zhang if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
17369eb03bb1SYinjun Zhang return -EOPNOTSUPP;
17379eb03bb1SYinjun Zhang
17389eb03bb1SYinjun Zhang if (!nn->fs.count || cmd->fs.location >= NFP_FS_MAX_ENTRY)
17399eb03bb1SYinjun Zhang return -EINVAL;
17409eb03bb1SYinjun Zhang
17419eb03bb1SYinjun Zhang list_for_each_entry(entry, &nn->fs.list, node) {
17429eb03bb1SYinjun Zhang if (entry->loc == cmd->fs.location) {
17439eb03bb1SYinjun Zhang err = nfp_net_fs_del_hw(nn, entry);
17449eb03bb1SYinjun Zhang if (err)
17459eb03bb1SYinjun Zhang return err;
17469eb03bb1SYinjun Zhang
17479eb03bb1SYinjun Zhang list_del(&entry->node);
17489eb03bb1SYinjun Zhang kfree(entry);
17499eb03bb1SYinjun Zhang nn->fs.count--;
17509eb03bb1SYinjun Zhang
17519eb03bb1SYinjun Zhang return 0;
17529eb03bb1SYinjun Zhang } else if (entry->loc > cmd->fs.location) {
17539eb03bb1SYinjun Zhang /* no need to continue */
17549eb03bb1SYinjun Zhang break;
17559eb03bb1SYinjun Zhang }
17569eb03bb1SYinjun Zhang }
17579eb03bb1SYinjun Zhang
17589eb03bb1SYinjun Zhang return -ENOENT;
17599eb03bb1SYinjun Zhang }
17609eb03bb1SYinjun Zhang
nfp_net_set_rxnfc(struct net_device * netdev,struct ethtool_rxnfc * cmd)17614c352362SJakub Kicinski static int nfp_net_set_rxnfc(struct net_device *netdev,
17624c352362SJakub Kicinski struct ethtool_rxnfc *cmd)
17634c352362SJakub Kicinski {
17644c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
17654c352362SJakub Kicinski
17664c352362SJakub Kicinski switch (cmd->cmd) {
17679eb03bb1SYinjun Zhang case ETHTOOL_SRXCLSRLINS:
17689eb03bb1SYinjun Zhang return nfp_net_fs_add(nn, cmd);
17699eb03bb1SYinjun Zhang case ETHTOOL_SRXCLSRLDEL:
17709eb03bb1SYinjun Zhang return nfp_net_fs_del(nn, cmd);
17714c352362SJakub Kicinski default:
17724c352362SJakub Kicinski return -EOPNOTSUPP;
17734c352362SJakub Kicinski }
17744c352362SJakub Kicinski }
17754c352362SJakub Kicinski
nfp_net_get_rxfh_indir_size(struct net_device * netdev)17764c352362SJakub Kicinski static u32 nfp_net_get_rxfh_indir_size(struct net_device *netdev)
17774c352362SJakub Kicinski {
17784c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
17794c352362SJakub Kicinski
1780611bdd49SEdwin Peer if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
17814c352362SJakub Kicinski return 0;
17824c352362SJakub Kicinski
17834c352362SJakub Kicinski return ARRAY_SIZE(nn->rss_itbl);
17844c352362SJakub Kicinski }
17854c352362SJakub Kicinski
nfp_net_get_rxfh_key_size(struct net_device * netdev)17864c352362SJakub Kicinski static u32 nfp_net_get_rxfh_key_size(struct net_device *netdev)
17874c352362SJakub Kicinski {
17889ff304bfSJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
17899ff304bfSJakub Kicinski
1790611bdd49SEdwin Peer if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
17919ff304bfSJakub Kicinski return -EOPNOTSUPP;
17929ff304bfSJakub Kicinski
17939ff304bfSJakub Kicinski return nfp_net_rss_key_sz(nn);
17944c352362SJakub Kicinski }
17954c352362SJakub Kicinski
nfp_net_get_rxfh(struct net_device * netdev,struct ethtool_rxfh_param * rxfh)1796fb6e30a7SAhmed Zaki static int nfp_net_get_rxfh(struct net_device *netdev,
1797fb6e30a7SAhmed Zaki struct ethtool_rxfh_param *rxfh)
17984c352362SJakub Kicinski {
17994c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
18004c352362SJakub Kicinski int i;
18014c352362SJakub Kicinski
1802611bdd49SEdwin Peer if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
18034c352362SJakub Kicinski return -EOPNOTSUPP;
18044c352362SJakub Kicinski
1805fb6e30a7SAhmed Zaki if (rxfh->indir)
18064c352362SJakub Kicinski for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
1807fb6e30a7SAhmed Zaki rxfh->indir[i] = nn->rss_itbl[i];
1808fb6e30a7SAhmed Zaki if (rxfh->key)
1809fb6e30a7SAhmed Zaki memcpy(rxfh->key, nn->rss_key, nfp_net_rss_key_sz(nn));
1810fb6e30a7SAhmed Zaki
1811fb6e30a7SAhmed Zaki rxfh->hfunc = nn->rss_hfunc;
1812fb6e30a7SAhmed Zaki if (rxfh->hfunc >= 1 << ETH_RSS_HASH_FUNCS_COUNT)
1813fb6e30a7SAhmed Zaki rxfh->hfunc = ETH_RSS_HASH_UNKNOWN;
18144c352362SJakub Kicinski
18154c352362SJakub Kicinski return 0;
18164c352362SJakub Kicinski }
18174c352362SJakub Kicinski
nfp_net_set_rxfh(struct net_device * netdev,struct ethtool_rxfh_param * rxfh,struct netlink_ext_ack * extack)18184c352362SJakub Kicinski static int nfp_net_set_rxfh(struct net_device *netdev,
1819fb6e30a7SAhmed Zaki struct ethtool_rxfh_param *rxfh,
1820fb6e30a7SAhmed Zaki struct netlink_ext_ack *extack)
18214c352362SJakub Kicinski {
18224c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
18234c352362SJakub Kicinski int i;
18244c352362SJakub Kicinski
1825611bdd49SEdwin Peer if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) ||
1826fb6e30a7SAhmed Zaki !(rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE ||
1827fb6e30a7SAhmed Zaki rxfh->hfunc == nn->rss_hfunc))
18284c352362SJakub Kicinski return -EOPNOTSUPP;
18294c352362SJakub Kicinski
1830fb6e30a7SAhmed Zaki if (!rxfh->key && !rxfh->indir)
18314c352362SJakub Kicinski return 0;
18324c352362SJakub Kicinski
1833fb6e30a7SAhmed Zaki if (rxfh->key) {
1834fb6e30a7SAhmed Zaki memcpy(nn->rss_key, rxfh->key, nfp_net_rss_key_sz(nn));
18354c352362SJakub Kicinski nfp_net_rss_write_key(nn);
18364c352362SJakub Kicinski }
1837fb6e30a7SAhmed Zaki if (rxfh->indir) {
18384c352362SJakub Kicinski for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
1839fb6e30a7SAhmed Zaki nn->rss_itbl[i] = rxfh->indir[i];
18404c352362SJakub Kicinski
18414c352362SJakub Kicinski nfp_net_rss_write_itbl(nn);
18424c352362SJakub Kicinski }
18434c352362SJakub Kicinski
18444c352362SJakub Kicinski return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_RSS);
18454c352362SJakub Kicinski }
18464c352362SJakub Kicinski
18474c352362SJakub Kicinski /* Dump BAR registers
18484c352362SJakub Kicinski */
nfp_net_get_regs_len(struct net_device * netdev)18494c352362SJakub Kicinski static int nfp_net_get_regs_len(struct net_device *netdev)
18504c352362SJakub Kicinski {
18514c352362SJakub Kicinski return NFP_NET_CFG_BAR_SZ;
18524c352362SJakub Kicinski }
18534c352362SJakub Kicinski
nfp_net_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)18544c352362SJakub Kicinski static void nfp_net_get_regs(struct net_device *netdev,
18554c352362SJakub Kicinski struct ethtool_regs *regs, void *p)
18564c352362SJakub Kicinski {
18574c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
18584c352362SJakub Kicinski u32 *regs_buf = p;
18594c352362SJakub Kicinski int i;
18604c352362SJakub Kicinski
18614c352362SJakub Kicinski regs->version = nn_readl(nn, NFP_NET_CFG_VERSION);
18624c352362SJakub Kicinski
18634c352362SJakub Kicinski for (i = 0; i < NFP_NET_CFG_BAR_SZ / sizeof(u32); i++)
1864d2b84397SJakub Kicinski regs_buf[i] = readl(nn->dp.ctrl_bar + (i * sizeof(u32)));
18654c352362SJakub Kicinski }
18664c352362SJakub Kicinski
nfp_net_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * ec,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)18674c352362SJakub Kicinski static int nfp_net_get_coalesce(struct net_device *netdev,
1868f3ccfda1SYufeng Mo struct ethtool_coalesce *ec,
1869f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal,
1870f3ccfda1SYufeng Mo struct netlink_ext_ack *extack)
18714c352362SJakub Kicinski {
18724c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
18734c352362SJakub Kicinski
18744c352362SJakub Kicinski if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
1875b0318e28SRyno Swart return -EOPNOTSUPP;
18764c352362SJakub Kicinski
18779d32e4e7SYinjun Zhang ec->use_adaptive_rx_coalesce = nn->rx_coalesce_adapt_on;
18789d32e4e7SYinjun Zhang ec->use_adaptive_tx_coalesce = nn->tx_coalesce_adapt_on;
18799d32e4e7SYinjun Zhang
18804c352362SJakub Kicinski ec->rx_coalesce_usecs = nn->rx_coalesce_usecs;
18814c352362SJakub Kicinski ec->rx_max_coalesced_frames = nn->rx_coalesce_max_frames;
18824c352362SJakub Kicinski ec->tx_coalesce_usecs = nn->tx_coalesce_usecs;
18834c352362SJakub Kicinski ec->tx_max_coalesced_frames = nn->tx_coalesce_max_frames;
18844c352362SJakub Kicinski
18854c352362SJakub Kicinski return 0;
18864c352362SJakub Kicinski }
18874c352362SJakub Kicinski
1888af623682SJakub Kicinski /* Other debug dumps
1889af623682SJakub Kicinski */
1890af623682SJakub Kicinski static int
nfp_dump_nsp_diag(struct nfp_app * app,struct ethtool_dump * dump,void * buffer)1891a2f4c3d9SJakub Kicinski nfp_dump_nsp_diag(struct nfp_app *app, struct ethtool_dump *dump, void *buffer)
1892af623682SJakub Kicinski {
1893af623682SJakub Kicinski struct nfp_resource *res;
1894af623682SJakub Kicinski int ret;
1895af623682SJakub Kicinski
1896a2f4c3d9SJakub Kicinski if (!app)
1897af623682SJakub Kicinski return -EOPNOTSUPP;
1898af623682SJakub Kicinski
1899af623682SJakub Kicinski dump->version = 1;
1900af623682SJakub Kicinski dump->flag = NFP_DUMP_NSP_DIAG;
1901af623682SJakub Kicinski
1902a2f4c3d9SJakub Kicinski res = nfp_resource_acquire(app->cpp, NFP_RESOURCE_NSP_DIAG);
1903af623682SJakub Kicinski if (IS_ERR(res))
1904af623682SJakub Kicinski return PTR_ERR(res);
1905af623682SJakub Kicinski
1906af623682SJakub Kicinski if (buffer) {
1907af623682SJakub Kicinski if (dump->len != nfp_resource_size(res)) {
1908af623682SJakub Kicinski ret = -EINVAL;
1909af623682SJakub Kicinski goto exit_release;
1910af623682SJakub Kicinski }
1911af623682SJakub Kicinski
1912a2f4c3d9SJakub Kicinski ret = nfp_cpp_read(app->cpp, nfp_resource_cpp_id(res),
1913af623682SJakub Kicinski nfp_resource_address(res),
1914af623682SJakub Kicinski buffer, dump->len);
1915af623682SJakub Kicinski if (ret != dump->len)
1916af623682SJakub Kicinski ret = ret < 0 ? ret : -EIO;
1917af623682SJakub Kicinski else
1918af623682SJakub Kicinski ret = 0;
1919af623682SJakub Kicinski } else {
1920af623682SJakub Kicinski dump->len = nfp_resource_size(res);
1921af623682SJakub Kicinski ret = 0;
1922af623682SJakub Kicinski }
1923af623682SJakub Kicinski exit_release:
1924af623682SJakub Kicinski nfp_resource_release(res);
1925af623682SJakub Kicinski
1926af623682SJakub Kicinski return ret;
1927af623682SJakub Kicinski }
1928af623682SJakub Kicinski
1929d79e19f5SCarl Heymann /* Set the dump flag/level. Calculate the dump length for flag > 0 only (new TLV
1930d79e19f5SCarl Heymann * based dumps), since flag 0 (default) calculates the length in
1931d79e19f5SCarl Heymann * nfp_app_get_dump_flag(), and we need to support triggering a level 0 dump
1932d79e19f5SCarl Heymann * without setting the flag first, for backward compatibility.
1933d79e19f5SCarl Heymann */
nfp_app_set_dump(struct net_device * netdev,struct ethtool_dump * val)1934a2f4c3d9SJakub Kicinski static int nfp_app_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1935af623682SJakub Kicinski {
1936a2f4c3d9SJakub Kicinski struct nfp_app *app = nfp_app_from_netdev(netdev);
1937d79e19f5SCarl Heymann s64 len;
1938af623682SJakub Kicinski
1939a2f4c3d9SJakub Kicinski if (!app)
1940af623682SJakub Kicinski return -EOPNOTSUPP;
1941af623682SJakub Kicinski
1942d79e19f5SCarl Heymann if (val->flag == NFP_DUMP_NSP_DIAG) {
1943d79e19f5SCarl Heymann app->pf->dump_flag = val->flag;
1944d79e19f5SCarl Heymann return 0;
1945d79e19f5SCarl Heymann }
1946d79e19f5SCarl Heymann
1947d79e19f5SCarl Heymann if (!app->pf->dumpspec)
1948d79e19f5SCarl Heymann return -EOPNOTSUPP;
1949d79e19f5SCarl Heymann
1950d79e19f5SCarl Heymann len = nfp_net_dump_calculate_size(app->pf, app->pf->dumpspec,
1951d79e19f5SCarl Heymann val->flag);
1952d79e19f5SCarl Heymann if (len < 0)
1953d79e19f5SCarl Heymann return len;
1954d79e19f5SCarl Heymann
1955d79e19f5SCarl Heymann app->pf->dump_flag = val->flag;
1956d79e19f5SCarl Heymann app->pf->dump_len = len;
1957af623682SJakub Kicinski
1958af623682SJakub Kicinski return 0;
1959af623682SJakub Kicinski }
1960af623682SJakub Kicinski
1961af623682SJakub Kicinski static int
nfp_app_get_dump_flag(struct net_device * netdev,struct ethtool_dump * dump)1962a2f4c3d9SJakub Kicinski nfp_app_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1963af623682SJakub Kicinski {
1964d79e19f5SCarl Heymann struct nfp_app *app = nfp_app_from_netdev(netdev);
1965d79e19f5SCarl Heymann
1966d79e19f5SCarl Heymann if (!app)
1967d79e19f5SCarl Heymann return -EOPNOTSUPP;
1968d79e19f5SCarl Heymann
1969d79e19f5SCarl Heymann if (app->pf->dump_flag == NFP_DUMP_NSP_DIAG)
1970d79e19f5SCarl Heymann return nfp_dump_nsp_diag(app, dump, NULL);
1971d79e19f5SCarl Heymann
1972d79e19f5SCarl Heymann dump->flag = app->pf->dump_flag;
1973d79e19f5SCarl Heymann dump->len = app->pf->dump_len;
1974d79e19f5SCarl Heymann
1975d79e19f5SCarl Heymann return 0;
1976af623682SJakub Kicinski }
1977af623682SJakub Kicinski
1978af623682SJakub Kicinski static int
nfp_app_get_dump_data(struct net_device * netdev,struct ethtool_dump * dump,void * buffer)1979a2f4c3d9SJakub Kicinski nfp_app_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1980af623682SJakub Kicinski void *buffer)
1981af623682SJakub Kicinski {
1982d79e19f5SCarl Heymann struct nfp_app *app = nfp_app_from_netdev(netdev);
1983d79e19f5SCarl Heymann
1984d79e19f5SCarl Heymann if (!app)
1985d79e19f5SCarl Heymann return -EOPNOTSUPP;
1986d79e19f5SCarl Heymann
1987d79e19f5SCarl Heymann if (app->pf->dump_flag == NFP_DUMP_NSP_DIAG)
1988d79e19f5SCarl Heymann return nfp_dump_nsp_diag(app, dump, buffer);
1989d79e19f5SCarl Heymann
1990d79e19f5SCarl Heymann dump->flag = app->pf->dump_flag;
1991d79e19f5SCarl Heymann dump->len = app->pf->dump_len;
1992d79e19f5SCarl Heymann
1993d79e19f5SCarl Heymann return nfp_net_dump_populate_buffer(app->pf, app->pf->dumpspec, dump,
1994d79e19f5SCarl Heymann buffer);
1995af623682SJakub Kicinski }
1996af623682SJakub Kicinski
199761f7c6f4SDirk van der Merwe static int
nfp_port_get_module_info(struct net_device * netdev,struct ethtool_modinfo * modinfo)199861f7c6f4SDirk van der Merwe nfp_port_get_module_info(struct net_device *netdev,
199961f7c6f4SDirk van der Merwe struct ethtool_modinfo *modinfo)
200061f7c6f4SDirk van der Merwe {
200161f7c6f4SDirk van der Merwe struct nfp_eth_table_port *eth_port;
200261f7c6f4SDirk van der Merwe struct nfp_port *port;
200361f7c6f4SDirk van der Merwe unsigned int read_len;
200461f7c6f4SDirk van der Merwe struct nfp_nsp *nsp;
200561f7c6f4SDirk van der Merwe int err = 0;
200661f7c6f4SDirk van der Merwe u8 data;
200761f7c6f4SDirk van der Merwe
200861f7c6f4SDirk van der Merwe port = nfp_port_from_netdev(netdev);
20090873016dSJaco Coetzee if (!port)
20100873016dSJaco Coetzee return -EOPNOTSUPP;
20110873016dSJaco Coetzee
20124ae97caeSYu Xiao /* update port state to get latest interface */
20134ae97caeSYu Xiao set_bit(NFP_PORT_CHANGED, &port->flags);
201461f7c6f4SDirk van der Merwe eth_port = nfp_port_get_eth_port(port);
201561f7c6f4SDirk van der Merwe if (!eth_port)
201661f7c6f4SDirk van der Merwe return -EOPNOTSUPP;
201761f7c6f4SDirk van der Merwe
201861f7c6f4SDirk van der Merwe nsp = nfp_nsp_open(port->app->cpp);
201961f7c6f4SDirk van der Merwe if (IS_ERR(nsp)) {
202061f7c6f4SDirk van der Merwe err = PTR_ERR(nsp);
202161f7c6f4SDirk van der Merwe netdev_err(netdev, "Failed to access the NSP: %d\n", err);
202261f7c6f4SDirk van der Merwe return err;
202361f7c6f4SDirk van der Merwe }
202461f7c6f4SDirk van der Merwe
202561f7c6f4SDirk van der Merwe if (!nfp_nsp_has_read_module_eeprom(nsp)) {
202661f7c6f4SDirk van der Merwe netdev_info(netdev, "reading module EEPROM not supported. Please update flash\n");
202761f7c6f4SDirk van der Merwe err = -EOPNOTSUPP;
202861f7c6f4SDirk van der Merwe goto exit_close_nsp;
202961f7c6f4SDirk van der Merwe }
203061f7c6f4SDirk van der Merwe
203161f7c6f4SDirk van der Merwe switch (eth_port->interface) {
203261f7c6f4SDirk van der Merwe case NFP_INTERFACE_SFP:
203361f7c6f4SDirk van der Merwe case NFP_INTERFACE_SFP28:
203461f7c6f4SDirk van der Merwe err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
203561f7c6f4SDirk van der Merwe SFP_SFF8472_COMPLIANCE, &data,
203661f7c6f4SDirk van der Merwe 1, &read_len);
203761f7c6f4SDirk van der Merwe if (err < 0)
203861f7c6f4SDirk van der Merwe goto exit_close_nsp;
203961f7c6f4SDirk van der Merwe
204061f7c6f4SDirk van der Merwe if (!data) {
204161f7c6f4SDirk van der Merwe modinfo->type = ETH_MODULE_SFF_8079;
204261f7c6f4SDirk van der Merwe modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
204361f7c6f4SDirk van der Merwe } else {
204461f7c6f4SDirk van der Merwe modinfo->type = ETH_MODULE_SFF_8472;
204561f7c6f4SDirk van der Merwe modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
204661f7c6f4SDirk van der Merwe }
204761f7c6f4SDirk van der Merwe break;
204861f7c6f4SDirk van der Merwe case NFP_INTERFACE_QSFP:
204961f7c6f4SDirk van der Merwe err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
205061f7c6f4SDirk van der Merwe SFP_SFF_REV_COMPLIANCE, &data,
205161f7c6f4SDirk van der Merwe 1, &read_len);
205261f7c6f4SDirk van der Merwe if (err < 0)
205361f7c6f4SDirk van der Merwe goto exit_close_nsp;
205461f7c6f4SDirk van der Merwe
205561f7c6f4SDirk van der Merwe if (data < 0x3) {
205661f7c6f4SDirk van der Merwe modinfo->type = ETH_MODULE_SFF_8436;
2057f3a72878SJaco Coetzee modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN;
205861f7c6f4SDirk van der Merwe } else {
205961f7c6f4SDirk van der Merwe modinfo->type = ETH_MODULE_SFF_8636;
2060f3a72878SJaco Coetzee modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
206161f7c6f4SDirk van der Merwe }
206261f7c6f4SDirk van der Merwe break;
206361f7c6f4SDirk van der Merwe case NFP_INTERFACE_QSFP28:
206461f7c6f4SDirk van der Merwe modinfo->type = ETH_MODULE_SFF_8636;
2065f3a72878SJaco Coetzee modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
206661f7c6f4SDirk van der Merwe break;
206761f7c6f4SDirk van der Merwe default:
206861f7c6f4SDirk van der Merwe netdev_err(netdev, "Unsupported module 0x%x detected\n",
206961f7c6f4SDirk van der Merwe eth_port->interface);
207061f7c6f4SDirk van der Merwe err = -EINVAL;
207161f7c6f4SDirk van der Merwe }
207261f7c6f4SDirk van der Merwe
207361f7c6f4SDirk van der Merwe exit_close_nsp:
207461f7c6f4SDirk van der Merwe nfp_nsp_close(nsp);
207561f7c6f4SDirk van der Merwe return err;
207661f7c6f4SDirk van der Merwe }
207761f7c6f4SDirk van der Merwe
207861f7c6f4SDirk van der Merwe static int
nfp_port_get_module_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * data)207961f7c6f4SDirk van der Merwe nfp_port_get_module_eeprom(struct net_device *netdev,
208061f7c6f4SDirk van der Merwe struct ethtool_eeprom *eeprom, u8 *data)
208161f7c6f4SDirk van der Merwe {
208261f7c6f4SDirk van der Merwe struct nfp_eth_table_port *eth_port;
208361f7c6f4SDirk van der Merwe struct nfp_port *port;
208461f7c6f4SDirk van der Merwe struct nfp_nsp *nsp;
208561f7c6f4SDirk van der Merwe int err;
208661f7c6f4SDirk van der Merwe
208761f7c6f4SDirk van der Merwe port = nfp_port_from_netdev(netdev);
208861f7c6f4SDirk van der Merwe eth_port = __nfp_port_get_eth_port(port);
208961f7c6f4SDirk van der Merwe if (!eth_port)
209061f7c6f4SDirk van der Merwe return -EOPNOTSUPP;
209161f7c6f4SDirk van der Merwe
209261f7c6f4SDirk van der Merwe nsp = nfp_nsp_open(port->app->cpp);
209361f7c6f4SDirk van der Merwe if (IS_ERR(nsp)) {
209461f7c6f4SDirk van der Merwe err = PTR_ERR(nsp);
209561f7c6f4SDirk van der Merwe netdev_err(netdev, "Failed to access the NSP: %d\n", err);
209661f7c6f4SDirk van der Merwe return err;
209761f7c6f4SDirk van der Merwe }
209861f7c6f4SDirk van der Merwe
209961f7c6f4SDirk van der Merwe if (!nfp_nsp_has_read_module_eeprom(nsp)) {
210061f7c6f4SDirk van der Merwe netdev_info(netdev, "reading module EEPROM not supported. Please update flash\n");
210161f7c6f4SDirk van der Merwe err = -EOPNOTSUPP;
210261f7c6f4SDirk van der Merwe goto exit_close_nsp;
210361f7c6f4SDirk van der Merwe }
210461f7c6f4SDirk van der Merwe
210561f7c6f4SDirk van der Merwe err = nfp_nsp_read_module_eeprom(nsp, eth_port->eth_index,
210661f7c6f4SDirk van der Merwe eeprom->offset, data, eeprom->len,
210761f7c6f4SDirk van der Merwe &eeprom->len);
210861f7c6f4SDirk van der Merwe if (err < 0) {
210961f7c6f4SDirk van der Merwe if (eeprom->len) {
211061f7c6f4SDirk van der Merwe netdev_warn(netdev,
211161f7c6f4SDirk van der Merwe "Incomplete read from module EEPROM: %d\n",
211261f7c6f4SDirk van der Merwe err);
211361f7c6f4SDirk van der Merwe err = 0;
211461f7c6f4SDirk van der Merwe } else {
211561f7c6f4SDirk van der Merwe netdev_err(netdev,
211661f7c6f4SDirk van der Merwe "Reading from module EEPROM failed: %d\n",
211761f7c6f4SDirk van der Merwe err);
211861f7c6f4SDirk van der Merwe }
211961f7c6f4SDirk van der Merwe }
212061f7c6f4SDirk van der Merwe
212161f7c6f4SDirk van der Merwe exit_close_nsp:
212261f7c6f4SDirk van der Merwe nfp_nsp_close(nsp);
212361f7c6f4SDirk van der Merwe return err;
212461f7c6f4SDirk van der Merwe }
212561f7c6f4SDirk 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)21264c352362SJakub Kicinski static int nfp_net_set_coalesce(struct net_device *netdev,
2127f3ccfda1SYufeng Mo struct ethtool_coalesce *ec,
2128f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal,
2129f3ccfda1SYufeng Mo struct netlink_ext_ack *extack)
21304c352362SJakub Kicinski {
21314c352362SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
21324c352362SJakub Kicinski unsigned int factor;
21334c352362SJakub Kicinski
21344c352362SJakub Kicinski /* Compute factor used to convert coalesce '_usecs' parameters to
21354c352362SJakub Kicinski * ME timestamp ticks. There are 16 ME clock cycles for each timestamp
21364c352362SJakub Kicinski * count.
21374c352362SJakub Kicinski */
21383bd6b2a8SDiana Wang factor = nn->tlv_caps.me_freq_mhz / 16;
21394c352362SJakub Kicinski
21404c352362SJakub Kicinski /* Each pair of (usecs, max_frames) fields specifies that interrupts
21414c352362SJakub Kicinski * should be coalesced until
21424c352362SJakub Kicinski * (usecs > 0 && time_since_first_completion >= usecs) ||
21434c352362SJakub Kicinski * (max_frames > 0 && completed_frames >= max_frames)
21444c352362SJakub Kicinski *
21454c352362SJakub Kicinski * It is illegal to set both usecs and max_frames to zero as this would
21464c352362SJakub Kicinski * cause interrupts to never be generated. To disable coalescing, set
21474c352362SJakub Kicinski * usecs = 0 and max_frames = 1.
21484c352362SJakub Kicinski *
21494c352362SJakub Kicinski * Some implementations ignore the value of max_frames and use the
21504c352362SJakub Kicinski * condition time_since_first_completion >= usecs
21514c352362SJakub Kicinski */
21524c352362SJakub Kicinski
21534c352362SJakub Kicinski if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
2154b0318e28SRyno Swart return -EOPNOTSUPP;
21554c352362SJakub Kicinski
21564c352362SJakub Kicinski /* ensure valid configuration */
2157b0318e28SRyno Swart if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames) {
2158b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack,
2159b0318e28SRyno Swart "rx-usecs and rx-frames cannot both be zero");
21604c352362SJakub Kicinski return -EINVAL;
2161b0318e28SRyno Swart }
21624c352362SJakub Kicinski
2163b0318e28SRyno Swart if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames) {
2164b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack,
2165b0318e28SRyno Swart "tx-usecs and tx-frames cannot both be zero");
21664c352362SJakub Kicinski return -EINVAL;
2167b0318e28SRyno Swart }
21684c352362SJakub Kicinski
2169b0318e28SRyno Swart if (nfp_net_coalesce_para_check(ec->rx_coalesce_usecs * factor)) {
2170b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack, "rx-usecs too large");
21714c352362SJakub Kicinski return -EINVAL;
2172b0318e28SRyno Swart }
21734c352362SJakub Kicinski
2174b0318e28SRyno Swart if (nfp_net_coalesce_para_check(ec->rx_max_coalesced_frames)) {
2175b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack, "rx-frames too large");
21764c352362SJakub Kicinski return -EINVAL;
2177b0318e28SRyno Swart }
2178b0318e28SRyno Swart
2179b0318e28SRyno Swart if (nfp_net_coalesce_para_check(ec->tx_coalesce_usecs * factor)) {
2180b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack, "tx-usecs too large");
2181b0318e28SRyno Swart return -EINVAL;
2182b0318e28SRyno Swart }
2183b0318e28SRyno Swart
2184b0318e28SRyno Swart if (nfp_net_coalesce_para_check(ec->tx_max_coalesced_frames)) {
2185b0318e28SRyno Swart NL_SET_ERR_MSG_MOD(extack, "tx-frames too large");
2186b0318e28SRyno Swart return -EINVAL;
2187b0318e28SRyno Swart }
21884c352362SJakub Kicinski
21894c352362SJakub Kicinski /* configuration is valid */
21909d32e4e7SYinjun Zhang nn->rx_coalesce_adapt_on = !!ec->use_adaptive_rx_coalesce;
21919d32e4e7SYinjun Zhang nn->tx_coalesce_adapt_on = !!ec->use_adaptive_tx_coalesce;
21929d32e4e7SYinjun Zhang
21934c352362SJakub Kicinski nn->rx_coalesce_usecs = ec->rx_coalesce_usecs;
21944c352362SJakub Kicinski nn->rx_coalesce_max_frames = ec->rx_max_coalesced_frames;
21954c352362SJakub Kicinski nn->tx_coalesce_usecs = ec->tx_coalesce_usecs;
21964c352362SJakub Kicinski nn->tx_coalesce_max_frames = ec->tx_max_coalesced_frames;
21974c352362SJakub Kicinski
21984c352362SJakub Kicinski /* write configuration to device */
21994c352362SJakub Kicinski nfp_net_coalesce_write_cfg(nn);
22004c352362SJakub Kicinski return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_IRQMOD);
22014c352362SJakub Kicinski }
22024c352362SJakub Kicinski
nfp_net_get_channels(struct net_device * netdev,struct ethtool_channels * channel)220381cc2e43SJakub Kicinski static void nfp_net_get_channels(struct net_device *netdev,
220481cc2e43SJakub Kicinski struct ethtool_channels *channel)
220581cc2e43SJakub Kicinski {
220681cc2e43SJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
2207ecd63a02SJakub Kicinski unsigned int num_tx_rings;
2208ecd63a02SJakub Kicinski
220979c12a75SJakub Kicinski num_tx_rings = nn->dp.num_tx_rings;
221079c12a75SJakub Kicinski if (nn->dp.xdp_prog)
221179c12a75SJakub Kicinski num_tx_rings -= nn->dp.num_rx_rings;
221281cc2e43SJakub Kicinski
221381cc2e43SJakub Kicinski channel->max_rx = min(nn->max_rx_rings, nn->max_r_vecs);
221481cc2e43SJakub Kicinski channel->max_tx = min(nn->max_tx_rings, nn->max_r_vecs);
221581cc2e43SJakub Kicinski channel->max_combined = min(channel->max_rx, channel->max_tx);
221681cc2e43SJakub Kicinski channel->max_other = NFP_NET_NON_Q_VECTORS;
221779c12a75SJakub Kicinski channel->combined_count = min(nn->dp.num_rx_rings, num_tx_rings);
221879c12a75SJakub Kicinski channel->rx_count = nn->dp.num_rx_rings - channel->combined_count;
2219ecd63a02SJakub Kicinski channel->tx_count = num_tx_rings - channel->combined_count;
222081cc2e43SJakub Kicinski channel->other_count = NFP_NET_NON_Q_VECTORS;
222181cc2e43SJakub Kicinski }
222281cc2e43SJakub Kicinski
nfp_net_set_num_rings(struct nfp_net * nn,unsigned int total_rx,unsigned int total_tx)2223164d1e9eSJakub Kicinski static int nfp_net_set_num_rings(struct nfp_net *nn, unsigned int total_rx,
2224164d1e9eSJakub Kicinski unsigned int total_tx)
2225164d1e9eSJakub Kicinski {
2226783496b0SJakub Kicinski struct nfp_net_dp *dp;
2227164d1e9eSJakub Kicinski
2228783496b0SJakub Kicinski dp = nfp_net_clone_dp(nn);
2229783496b0SJakub Kicinski if (!dp)
2230783496b0SJakub Kicinski return -ENOMEM;
2231783496b0SJakub Kicinski
2232892a7f70SJakub Kicinski dp->num_rx_rings = total_rx;
2233892a7f70SJakub Kicinski dp->num_tx_rings = total_tx;
2234892a7f70SJakub Kicinski /* nfp_net_check_config() will catch num_tx_rings > nn->max_tx_rings */
2235892a7f70SJakub Kicinski if (dp->xdp_prog)
2236892a7f70SJakub Kicinski dp->num_tx_rings += total_rx;
2237892a7f70SJakub Kicinski
2238d957c0f7SJakub Kicinski return nfp_net_ring_reconfig(nn, dp, NULL);
2239164d1e9eSJakub Kicinski }
2240164d1e9eSJakub Kicinski
nfp_net_set_channels(struct net_device * netdev,struct ethtool_channels * channel)2241164d1e9eSJakub Kicinski static int nfp_net_set_channels(struct net_device *netdev,
2242164d1e9eSJakub Kicinski struct ethtool_channels *channel)
2243164d1e9eSJakub Kicinski {
2244164d1e9eSJakub Kicinski struct nfp_net *nn = netdev_priv(netdev);
2245164d1e9eSJakub Kicinski unsigned int total_rx, total_tx;
2246164d1e9eSJakub Kicinski
2247164d1e9eSJakub Kicinski /* Reject unsupported */
22484df6ff2aSJakub Kicinski if (channel->other_count != NFP_NET_NON_Q_VECTORS ||
2249164d1e9eSJakub Kicinski (channel->rx_count && channel->tx_count))
2250164d1e9eSJakub Kicinski return -EINVAL;
2251164d1e9eSJakub Kicinski
2252164d1e9eSJakub Kicinski total_rx = channel->combined_count + channel->rx_count;
2253164d1e9eSJakub Kicinski total_tx = channel->combined_count + channel->tx_count;
2254164d1e9eSJakub Kicinski
2255164d1e9eSJakub Kicinski if (total_rx > min(nn->max_rx_rings, nn->max_r_vecs) ||
2256164d1e9eSJakub Kicinski total_tx > min(nn->max_tx_rings, nn->max_r_vecs))
2257164d1e9eSJakub Kicinski return -EINVAL;
2258164d1e9eSJakub Kicinski
2259164d1e9eSJakub Kicinski return nfp_net_set_num_rings(nn, total_rx, total_tx);
2260164d1e9eSJakub Kicinski }
2261164d1e9eSJakub Kicinski
nfp_port_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)22624540c29aSYu Xiao static int nfp_port_set_pauseparam(struct net_device *netdev,
22634540c29aSYu Xiao struct ethtool_pauseparam *pause)
22644540c29aSYu Xiao {
22654540c29aSYu Xiao struct nfp_eth_table_port *eth_port;
22664540c29aSYu Xiao struct nfp_port *port;
22674540c29aSYu Xiao int err;
22684540c29aSYu Xiao
22694540c29aSYu Xiao port = nfp_port_from_netdev(netdev);
22704540c29aSYu Xiao eth_port = nfp_port_get_eth_port(port);
22714540c29aSYu Xiao if (!eth_port)
22724540c29aSYu Xiao return -EOPNOTSUPP;
22734540c29aSYu Xiao
22744540c29aSYu Xiao if (pause->autoneg != AUTONEG_DISABLE)
22754540c29aSYu Xiao return -EOPNOTSUPP;
22764540c29aSYu Xiao
22774540c29aSYu Xiao err = nfp_eth_set_pauseparam(port->app->cpp, eth_port->index,
22784540c29aSYu Xiao pause->tx_pause, pause->rx_pause);
22794540c29aSYu Xiao if (!err)
22804540c29aSYu Xiao /* Only refresh if we did something */
22814540c29aSYu Xiao nfp_net_refresh_port_table(port);
22824540c29aSYu Xiao
22834540c29aSYu Xiao return err < 0 ? err : 0;
22844540c29aSYu Xiao }
22854540c29aSYu Xiao
nfp_port_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)2286382f99c4SYinjun Zhang static void nfp_port_get_pauseparam(struct net_device *netdev,
2287382f99c4SYinjun Zhang struct ethtool_pauseparam *pause)
2288382f99c4SYinjun Zhang {
2289382f99c4SYinjun Zhang struct nfp_eth_table_port *eth_port;
2290382f99c4SYinjun Zhang struct nfp_port *port;
2291382f99c4SYinjun Zhang
2292382f99c4SYinjun Zhang port = nfp_port_from_netdev(netdev);
2293382f99c4SYinjun Zhang eth_port = nfp_port_get_eth_port(port);
2294382f99c4SYinjun Zhang if (!eth_port)
2295382f99c4SYinjun Zhang return;
2296382f99c4SYinjun Zhang
22974540c29aSYu Xiao /* Currently pause frame autoneg is fixed */
2298382f99c4SYinjun Zhang pause->autoneg = AUTONEG_DISABLE;
22994540c29aSYu Xiao pause->rx_pause = eth_port->rx_pause;
23004540c29aSYu Xiao pause->tx_pause = eth_port->tx_pause;
2301382f99c4SYinjun Zhang }
2302382f99c4SYinjun Zhang
nfp_net_set_phys_id(struct net_device * netdev,enum ethtool_phys_id_state state)2303ccb9bc1dSSixiang Chen static int nfp_net_set_phys_id(struct net_device *netdev,
2304ccb9bc1dSSixiang Chen enum ethtool_phys_id_state state)
2305ccb9bc1dSSixiang Chen {
2306ccb9bc1dSSixiang Chen struct nfp_eth_table_port *eth_port;
2307ccb9bc1dSSixiang Chen struct nfp_port *port;
2308ccb9bc1dSSixiang Chen int err;
2309ccb9bc1dSSixiang Chen
2310ccb9bc1dSSixiang Chen port = nfp_port_from_netdev(netdev);
2311ccb9bc1dSSixiang Chen eth_port = __nfp_port_get_eth_port(port);
2312ccb9bc1dSSixiang Chen if (!eth_port)
2313ccb9bc1dSSixiang Chen return -EOPNOTSUPP;
2314ccb9bc1dSSixiang Chen
2315ccb9bc1dSSixiang Chen switch (state) {
2316ccb9bc1dSSixiang Chen case ETHTOOL_ID_ACTIVE:
2317ccb9bc1dSSixiang Chen /* Control LED to blink */
2318ccb9bc1dSSixiang Chen err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 1);
2319ccb9bc1dSSixiang Chen break;
2320ccb9bc1dSSixiang Chen
2321ccb9bc1dSSixiang Chen case ETHTOOL_ID_INACTIVE:
2322ccb9bc1dSSixiang Chen /* Control LED to normal mode */
2323ccb9bc1dSSixiang Chen err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 0);
2324ccb9bc1dSSixiang Chen break;
2325ccb9bc1dSSixiang Chen
2326ccb9bc1dSSixiang Chen case ETHTOOL_ID_ON:
2327ccb9bc1dSSixiang Chen case ETHTOOL_ID_OFF:
2328ccb9bc1dSSixiang Chen default:
2329ccb9bc1dSSixiang Chen return -EOPNOTSUPP;
2330ccb9bc1dSSixiang Chen }
2331ccb9bc1dSSixiang Chen
2332ccb9bc1dSSixiang Chen return err;
2333ccb9bc1dSSixiang Chen }
2334ccb9bc1dSSixiang Chen
2335e6686745SBaowen Zheng #define NFP_EEPROM_LEN ETH_ALEN
2336e6686745SBaowen Zheng
2337e6686745SBaowen Zheng static int
nfp_net_get_eeprom_len(struct net_device * netdev)2338e6686745SBaowen Zheng nfp_net_get_eeprom_len(struct net_device *netdev)
2339e6686745SBaowen Zheng {
2340e6686745SBaowen Zheng struct nfp_eth_table_port *eth_port;
2341e6686745SBaowen Zheng struct nfp_port *port;
2342e6686745SBaowen Zheng
2343e6686745SBaowen Zheng port = nfp_port_from_netdev(netdev);
2344e6686745SBaowen Zheng eth_port = __nfp_port_get_eth_port(port);
2345e6686745SBaowen Zheng if (!eth_port)
2346e6686745SBaowen Zheng return 0;
2347e6686745SBaowen Zheng
2348e6686745SBaowen Zheng return NFP_EEPROM_LEN;
2349e6686745SBaowen Zheng }
2350e6686745SBaowen Zheng
2351e6686745SBaowen Zheng static int
nfp_net_get_nsp_hwindex(struct net_device * netdev,struct nfp_nsp ** nspptr,u32 * index)2352e6686745SBaowen Zheng nfp_net_get_nsp_hwindex(struct net_device *netdev,
2353e6686745SBaowen Zheng struct nfp_nsp **nspptr,
2354e6686745SBaowen Zheng u32 *index)
2355e6686745SBaowen Zheng {
2356e6686745SBaowen Zheng struct nfp_eth_table_port *eth_port;
2357e6686745SBaowen Zheng struct nfp_port *port;
2358e6686745SBaowen Zheng struct nfp_nsp *nsp;
2359e6686745SBaowen Zheng int err;
2360e6686745SBaowen Zheng
2361e6686745SBaowen Zheng port = nfp_port_from_netdev(netdev);
2362e6686745SBaowen Zheng eth_port = __nfp_port_get_eth_port(port);
2363e6686745SBaowen Zheng if (!eth_port)
2364e6686745SBaowen Zheng return -EOPNOTSUPP;
2365e6686745SBaowen Zheng
2366e6686745SBaowen Zheng nsp = nfp_nsp_open(port->app->cpp);
2367e6686745SBaowen Zheng if (IS_ERR(nsp)) {
2368e6686745SBaowen Zheng err = PTR_ERR(nsp);
2369e6686745SBaowen Zheng netdev_err(netdev, "Failed to access the NSP: %d\n", err);
2370e6686745SBaowen Zheng return err;
2371e6686745SBaowen Zheng }
2372e6686745SBaowen Zheng
2373e6686745SBaowen Zheng if (!nfp_nsp_has_hwinfo_lookup(nsp)) {
2374e6686745SBaowen Zheng netdev_err(netdev, "NSP doesn't support PF MAC generation\n");
2375e6686745SBaowen Zheng nfp_nsp_close(nsp);
2376e6686745SBaowen Zheng return -EOPNOTSUPP;
2377e6686745SBaowen Zheng }
2378e6686745SBaowen Zheng
2379e6686745SBaowen Zheng *nspptr = nsp;
2380e6686745SBaowen Zheng *index = eth_port->eth_index;
2381e6686745SBaowen Zheng
2382e6686745SBaowen Zheng return 0;
2383e6686745SBaowen Zheng }
2384e6686745SBaowen Zheng
2385e6686745SBaowen Zheng static int
nfp_net_get_port_mac_by_hwinfo(struct net_device * netdev,u8 * mac_addr)2386e6686745SBaowen Zheng nfp_net_get_port_mac_by_hwinfo(struct net_device *netdev,
2387e6686745SBaowen Zheng u8 *mac_addr)
2388e6686745SBaowen Zheng {
2389e6686745SBaowen Zheng char hwinfo[32] = {};
2390e6686745SBaowen Zheng struct nfp_nsp *nsp;
2391e6686745SBaowen Zheng u32 index;
2392e6686745SBaowen Zheng int err;
2393e6686745SBaowen Zheng
2394e6686745SBaowen Zheng err = nfp_net_get_nsp_hwindex(netdev, &nsp, &index);
2395e6686745SBaowen Zheng if (err)
2396e6686745SBaowen Zheng return err;
2397e6686745SBaowen Zheng
2398e6686745SBaowen Zheng snprintf(hwinfo, sizeof(hwinfo), "eth%u.mac", index);
2399e6686745SBaowen Zheng err = nfp_nsp_hwinfo_lookup(nsp, hwinfo, sizeof(hwinfo));
2400e6686745SBaowen Zheng nfp_nsp_close(nsp);
2401e6686745SBaowen Zheng if (err) {
2402e6686745SBaowen Zheng netdev_err(netdev, "Reading persistent MAC address failed: %d\n",
2403e6686745SBaowen Zheng err);
2404e6686745SBaowen Zheng return -EOPNOTSUPP;
2405e6686745SBaowen Zheng }
2406e6686745SBaowen Zheng
2407e6686745SBaowen Zheng if (sscanf(hwinfo, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2408e6686745SBaowen Zheng &mac_addr[0], &mac_addr[1], &mac_addr[2],
2409e6686745SBaowen Zheng &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
2410e6686745SBaowen Zheng netdev_err(netdev, "Can't parse persistent MAC address (%s)\n",
2411e6686745SBaowen Zheng hwinfo);
2412e6686745SBaowen Zheng return -EOPNOTSUPP;
2413e6686745SBaowen Zheng }
2414e6686745SBaowen Zheng
2415e6686745SBaowen Zheng return 0;
2416e6686745SBaowen Zheng }
2417e6686745SBaowen Zheng
2418e6686745SBaowen Zheng static int
nfp_net_set_port_mac_by_hwinfo(struct net_device * netdev,u8 * mac_addr)2419e6686745SBaowen Zheng nfp_net_set_port_mac_by_hwinfo(struct net_device *netdev,
2420e6686745SBaowen Zheng u8 *mac_addr)
2421e6686745SBaowen Zheng {
2422e6686745SBaowen Zheng char hwinfo[32] = {};
2423e6686745SBaowen Zheng struct nfp_nsp *nsp;
2424e6686745SBaowen Zheng u32 index;
2425e6686745SBaowen Zheng int err;
2426e6686745SBaowen Zheng
2427e6686745SBaowen Zheng err = nfp_net_get_nsp_hwindex(netdev, &nsp, &index);
2428e6686745SBaowen Zheng if (err)
2429e6686745SBaowen Zheng return err;
2430e6686745SBaowen Zheng
2431e6686745SBaowen Zheng snprintf(hwinfo, sizeof(hwinfo),
2432e6686745SBaowen Zheng "eth%u.mac=%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2433e6686745SBaowen Zheng index, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
2434e6686745SBaowen Zheng mac_addr[4], mac_addr[5]);
2435e6686745SBaowen Zheng
2436e6686745SBaowen Zheng err = nfp_nsp_hwinfo_set(nsp, hwinfo, sizeof(hwinfo));
2437e6686745SBaowen Zheng nfp_nsp_close(nsp);
2438e6686745SBaowen Zheng if (err) {
2439e6686745SBaowen Zheng netdev_err(netdev, "HWinfo set failed: %d, hwinfo: %s\n",
2440e6686745SBaowen Zheng err, hwinfo);
2441e6686745SBaowen Zheng return -EOPNOTSUPP;
2442e6686745SBaowen Zheng }
2443e6686745SBaowen Zheng
2444e6686745SBaowen Zheng return 0;
2445e6686745SBaowen Zheng }
2446e6686745SBaowen Zheng
2447e6686745SBaowen Zheng static int
nfp_net_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)2448e6686745SBaowen Zheng nfp_net_get_eeprom(struct net_device *netdev,
2449e6686745SBaowen Zheng struct ethtool_eeprom *eeprom, u8 *bytes)
2450e6686745SBaowen Zheng {
245174b4f173SJames Hershaw struct nfp_app *app = nfp_app_from_netdev(netdev);
2452e6686745SBaowen Zheng u8 buf[NFP_EEPROM_LEN] = {};
2453e6686745SBaowen Zheng
2454e6686745SBaowen Zheng if (nfp_net_get_port_mac_by_hwinfo(netdev, buf))
2455e6686745SBaowen Zheng return -EOPNOTSUPP;
2456e6686745SBaowen Zheng
2457f8175547SJames Hershaw if (eeprom->len == 0)
2458f8175547SJames Hershaw return -EINVAL;
2459f8175547SJames Hershaw
246074b4f173SJames Hershaw eeprom->magic = app->pdev->vendor | (app->pdev->device << 16);
2461e6686745SBaowen Zheng memcpy(bytes, buf + eeprom->offset, eeprom->len);
2462e6686745SBaowen Zheng
2463e6686745SBaowen Zheng return 0;
2464e6686745SBaowen Zheng }
2465e6686745SBaowen Zheng
2466e6686745SBaowen Zheng static int
nfp_net_set_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)2467e6686745SBaowen Zheng nfp_net_set_eeprom(struct net_device *netdev,
2468e6686745SBaowen Zheng struct ethtool_eeprom *eeprom, u8 *bytes)
2469e6686745SBaowen Zheng {
247074b4f173SJames Hershaw struct nfp_app *app = nfp_app_from_netdev(netdev);
2471e6686745SBaowen Zheng u8 buf[NFP_EEPROM_LEN] = {};
2472e6686745SBaowen Zheng
2473f8175547SJames Hershaw if (nfp_net_get_port_mac_by_hwinfo(netdev, buf))
2474f8175547SJames Hershaw return -EOPNOTSUPP;
2475f8175547SJames Hershaw
2476e6686745SBaowen Zheng if (eeprom->len == 0)
2477e6686745SBaowen Zheng return -EINVAL;
2478e6686745SBaowen Zheng
247974b4f173SJames Hershaw if (eeprom->magic != (app->pdev->vendor | app->pdev->device << 16))
2480e6686745SBaowen Zheng return -EINVAL;
2481e6686745SBaowen Zheng
2482e6686745SBaowen Zheng memcpy(buf + eeprom->offset, bytes, eeprom->len);
2483e6686745SBaowen Zheng if (nfp_net_set_port_mac_by_hwinfo(netdev, buf))
2484e6686745SBaowen Zheng return -EOPNOTSUPP;
2485e6686745SBaowen Zheng
2486e6686745SBaowen Zheng return 0;
2487e6686745SBaowen Zheng }
2488e6686745SBaowen Zheng
24894c352362SJakub Kicinski static const struct ethtool_ops nfp_net_ethtool_ops = {
24900e72ea19SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
24919d32e4e7SYinjun Zhang ETHTOOL_COALESCE_MAX_FRAMES |
24929d32e4e7SYinjun Zhang ETHTOOL_COALESCE_USE_ADAPTIVE,
24934c352362SJakub Kicinski .get_drvinfo = nfp_net_get_drvinfo,
24942820a400SFei Qin .nway_reset = nfp_net_nway_reset,
24952370def2SJakub Kicinski .get_link = ethtool_op_get_link,
24964c352362SJakub Kicinski .get_ringparam = nfp_net_get_ringparam,
24974c352362SJakub Kicinski .set_ringparam = nfp_net_set_ringparam,
249815137daeSFei Qin .self_test = nfp_net_self_test,
24994c352362SJakub Kicinski .get_strings = nfp_net_get_strings,
25004c352362SJakub Kicinski .get_ethtool_stats = nfp_net_get_stats,
25014c352362SJakub Kicinski .get_sset_count = nfp_net_get_sset_count,
25024c352362SJakub Kicinski .get_rxnfc = nfp_net_get_rxnfc,
25034c352362SJakub Kicinski .set_rxnfc = nfp_net_set_rxnfc,
25044c352362SJakub Kicinski .get_rxfh_indir_size = nfp_net_get_rxfh_indir_size,
25054c352362SJakub Kicinski .get_rxfh_key_size = nfp_net_get_rxfh_key_size,
25064c352362SJakub Kicinski .get_rxfh = nfp_net_get_rxfh,
25074c352362SJakub Kicinski .set_rxfh = nfp_net_set_rxfh,
2508*6bfd8cf3SJakub Kicinski .get_rxfh_fields = nfp_net_get_rxfh_fields,
2509*6bfd8cf3SJakub Kicinski .set_rxfh_fields = nfp_net_set_rxfh_fields,
25104c352362SJakub Kicinski .get_regs_len = nfp_net_get_regs_len,
25114c352362SJakub Kicinski .get_regs = nfp_net_get_regs,
2512a2f4c3d9SJakub Kicinski .set_dump = nfp_app_set_dump,
2513a2f4c3d9SJakub Kicinski .get_dump_flag = nfp_app_get_dump_flag,
2514a2f4c3d9SJakub Kicinski .get_dump_data = nfp_app_get_dump_data,
2515e6686745SBaowen Zheng .get_eeprom_len = nfp_net_get_eeprom_len,
2516e6686745SBaowen Zheng .get_eeprom = nfp_net_get_eeprom,
2517e6686745SBaowen Zheng .set_eeprom = nfp_net_set_eeprom,
251861f7c6f4SDirk van der Merwe .get_module_info = nfp_port_get_module_info,
251961f7c6f4SDirk van der Merwe .get_module_eeprom = nfp_port_get_module_eeprom,
25204c352362SJakub Kicinski .get_coalesce = nfp_net_get_coalesce,
25214c352362SJakub Kicinski .set_coalesce = nfp_net_set_coalesce,
252281cc2e43SJakub Kicinski .get_channels = nfp_net_get_channels,
2523164d1e9eSJakub Kicinski .set_channels = nfp_net_set_channels,
2524265aeb51SJakub Kicinski .get_link_ksettings = nfp_net_get_link_ksettings,
25257c698737SJakub Kicinski .set_link_ksettings = nfp_net_set_link_ksettings,
25260d087093SDirk van der Merwe .get_fecparam = nfp_port_get_fecparam,
25270d087093SDirk van der Merwe .set_fecparam = nfp_port_set_fecparam,
25284540c29aSYu Xiao .set_pauseparam = nfp_port_set_pauseparam,
2529382f99c4SYinjun Zhang .get_pauseparam = nfp_port_get_pauseparam,
2530ccb9bc1dSSixiang Chen .set_phys_id = nfp_net_set_phys_id,
25317453d7a6SYinjun Zhang .get_ts_info = ethtool_op_get_ts_info,
25324c352362SJakub Kicinski };
25334c352362SJakub Kicinski
253406726f30SJakub Kicinski const struct ethtool_ops nfp_port_ethtool_ops = {
25359e4c2cfcSJakub Kicinski .get_drvinfo = nfp_app_get_drvinfo,
25362820a400SFei Qin .nway_reset = nfp_net_nway_reset,
253706726f30SJakub Kicinski .get_link = ethtool_op_get_link,
2538899a37adSJakub Kicinski .get_strings = nfp_port_get_strings,
2539899a37adSJakub Kicinski .get_ethtool_stats = nfp_port_get_stats,
254015137daeSFei Qin .self_test = nfp_net_self_test,
2541899a37adSJakub Kicinski .get_sset_count = nfp_port_get_sset_count,
2542a2f4c3d9SJakub Kicinski .set_dump = nfp_app_set_dump,
2543a2f4c3d9SJakub Kicinski .get_dump_flag = nfp_app_get_dump_flag,
2544a2f4c3d9SJakub Kicinski .get_dump_data = nfp_app_get_dump_data,
254574b4f173SJames Hershaw .get_eeprom_len = nfp_net_get_eeprom_len,
254674b4f173SJames Hershaw .get_eeprom = nfp_net_get_eeprom,
254774b4f173SJames Hershaw .set_eeprom = nfp_net_set_eeprom,
254861f7c6f4SDirk van der Merwe .get_module_info = nfp_port_get_module_info,
254961f7c6f4SDirk van der Merwe .get_module_eeprom = nfp_port_get_module_eeprom,
2550a564d30eSDirk van der Merwe .get_link_ksettings = nfp_net_get_link_ksettings,
2551a564d30eSDirk van der Merwe .set_link_ksettings = nfp_net_set_link_ksettings,
25520d087093SDirk van der Merwe .get_fecparam = nfp_port_get_fecparam,
25530d087093SDirk van der Merwe .set_fecparam = nfp_port_set_fecparam,
25544540c29aSYu Xiao .set_pauseparam = nfp_port_set_pauseparam,
2555382f99c4SYinjun Zhang .get_pauseparam = nfp_port_get_pauseparam,
2556ccb9bc1dSSixiang Chen .set_phys_id = nfp_net_set_phys_id,
255706726f30SJakub Kicinski };
255806726f30SJakub Kicinski
nfp_net_set_ethtool_ops(struct net_device * netdev)25594c352362SJakub Kicinski void nfp_net_set_ethtool_ops(struct net_device *netdev)
25604c352362SJakub Kicinski {
25614c352362SJakub Kicinski netdev->ethtool_ops = &nfp_net_ethtool_ops;
25624c352362SJakub Kicinski }
2563