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