162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* ethtool support for ice */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "ice.h"
762306a36Sopenharmony_ci#include "ice_ethtool.h"
862306a36Sopenharmony_ci#include "ice_flow.h"
962306a36Sopenharmony_ci#include "ice_fltr.h"
1062306a36Sopenharmony_ci#include "ice_lib.h"
1162306a36Sopenharmony_ci#include "ice_dcb_lib.h"
1262306a36Sopenharmony_ci#include <net/dcbnl.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct ice_stats {
1562306a36Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
1662306a36Sopenharmony_ci	int sizeof_stat;
1762306a36Sopenharmony_ci	int stat_offset;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define ICE_STAT(_type, _name, _stat) { \
2162306a36Sopenharmony_ci	.stat_string = _name, \
2262306a36Sopenharmony_ci	.sizeof_stat = sizeof_field(_type, _stat), \
2362306a36Sopenharmony_ci	.stat_offset = offsetof(_type, _stat) \
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ICE_VSI_STAT(_name, _stat) \
2762306a36Sopenharmony_ci		ICE_STAT(struct ice_vsi, _name, _stat)
2862306a36Sopenharmony_ci#define ICE_PF_STAT(_name, _stat) \
2962306a36Sopenharmony_ci		ICE_STAT(struct ice_pf, _name, _stat)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int ice_q_stats_len(struct net_device *netdev)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return ((np->vsi->alloc_txq + np->vsi->alloc_rxq) *
3662306a36Sopenharmony_ci		(sizeof(struct ice_q_stats) / sizeof(u64)));
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define ICE_PF_STATS_LEN	ARRAY_SIZE(ice_gstrings_pf_stats)
4062306a36Sopenharmony_ci#define ICE_VSI_STATS_LEN	ARRAY_SIZE(ice_gstrings_vsi_stats)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define ICE_PFC_STATS_LEN ( \
4362306a36Sopenharmony_ci		(sizeof_field(struct ice_pf, stats.priority_xoff_rx) + \
4462306a36Sopenharmony_ci		 sizeof_field(struct ice_pf, stats.priority_xon_rx) + \
4562306a36Sopenharmony_ci		 sizeof_field(struct ice_pf, stats.priority_xoff_tx) + \
4662306a36Sopenharmony_ci		 sizeof_field(struct ice_pf, stats.priority_xon_tx)) \
4762306a36Sopenharmony_ci		 / sizeof(u64))
4862306a36Sopenharmony_ci#define ICE_ALL_STATS_LEN(n)	(ICE_PF_STATS_LEN + ICE_PFC_STATS_LEN + \
4962306a36Sopenharmony_ci				 ICE_VSI_STATS_LEN + ice_q_stats_len(n))
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const struct ice_stats ice_gstrings_vsi_stats[] = {
5262306a36Sopenharmony_ci	ICE_VSI_STAT("rx_unicast", eth_stats.rx_unicast),
5362306a36Sopenharmony_ci	ICE_VSI_STAT("tx_unicast", eth_stats.tx_unicast),
5462306a36Sopenharmony_ci	ICE_VSI_STAT("rx_multicast", eth_stats.rx_multicast),
5562306a36Sopenharmony_ci	ICE_VSI_STAT("tx_multicast", eth_stats.tx_multicast),
5662306a36Sopenharmony_ci	ICE_VSI_STAT("rx_broadcast", eth_stats.rx_broadcast),
5762306a36Sopenharmony_ci	ICE_VSI_STAT("tx_broadcast", eth_stats.tx_broadcast),
5862306a36Sopenharmony_ci	ICE_VSI_STAT("rx_bytes", eth_stats.rx_bytes),
5962306a36Sopenharmony_ci	ICE_VSI_STAT("tx_bytes", eth_stats.tx_bytes),
6062306a36Sopenharmony_ci	ICE_VSI_STAT("rx_dropped", eth_stats.rx_discards),
6162306a36Sopenharmony_ci	ICE_VSI_STAT("rx_unknown_protocol", eth_stats.rx_unknown_protocol),
6262306a36Sopenharmony_ci	ICE_VSI_STAT("rx_alloc_fail", rx_buf_failed),
6362306a36Sopenharmony_ci	ICE_VSI_STAT("rx_pg_alloc_fail", rx_page_failed),
6462306a36Sopenharmony_ci	ICE_VSI_STAT("tx_errors", eth_stats.tx_errors),
6562306a36Sopenharmony_ci	ICE_VSI_STAT("tx_linearize", tx_linearize),
6662306a36Sopenharmony_ci	ICE_VSI_STAT("tx_busy", tx_busy),
6762306a36Sopenharmony_ci	ICE_VSI_STAT("tx_restart", tx_restart),
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cienum ice_ethtool_test_id {
7162306a36Sopenharmony_ci	ICE_ETH_TEST_REG = 0,
7262306a36Sopenharmony_ci	ICE_ETH_TEST_EEPROM,
7362306a36Sopenharmony_ci	ICE_ETH_TEST_INTR,
7462306a36Sopenharmony_ci	ICE_ETH_TEST_LOOP,
7562306a36Sopenharmony_ci	ICE_ETH_TEST_LINK,
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic const char ice_gstrings_test[][ETH_GSTRING_LEN] = {
7962306a36Sopenharmony_ci	"Register test  (offline)",
8062306a36Sopenharmony_ci	"EEPROM test    (offline)",
8162306a36Sopenharmony_ci	"Interrupt test (offline)",
8262306a36Sopenharmony_ci	"Loopback test  (offline)",
8362306a36Sopenharmony_ci	"Link test   (on/offline)",
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define ICE_TEST_LEN (sizeof(ice_gstrings_test) / ETH_GSTRING_LEN)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* These PF_STATs might look like duplicates of some NETDEV_STATs,
8962306a36Sopenharmony_ci * but they aren't. This device is capable of supporting multiple
9062306a36Sopenharmony_ci * VSIs/netdevs on a single PF. The NETDEV_STATs are for individual
9162306a36Sopenharmony_ci * netdevs whereas the PF_STATs are for the physical function that's
9262306a36Sopenharmony_ci * hosting these netdevs.
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * The PF_STATs are appended to the netdev stats only when ethtool -S
9562306a36Sopenharmony_ci * is queried on the base PF netdev.
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic const struct ice_stats ice_gstrings_pf_stats[] = {
9862306a36Sopenharmony_ci	ICE_PF_STAT("rx_bytes.nic", stats.eth.rx_bytes),
9962306a36Sopenharmony_ci	ICE_PF_STAT("tx_bytes.nic", stats.eth.tx_bytes),
10062306a36Sopenharmony_ci	ICE_PF_STAT("rx_unicast.nic", stats.eth.rx_unicast),
10162306a36Sopenharmony_ci	ICE_PF_STAT("tx_unicast.nic", stats.eth.tx_unicast),
10262306a36Sopenharmony_ci	ICE_PF_STAT("rx_multicast.nic", stats.eth.rx_multicast),
10362306a36Sopenharmony_ci	ICE_PF_STAT("tx_multicast.nic", stats.eth.tx_multicast),
10462306a36Sopenharmony_ci	ICE_PF_STAT("rx_broadcast.nic", stats.eth.rx_broadcast),
10562306a36Sopenharmony_ci	ICE_PF_STAT("tx_broadcast.nic", stats.eth.tx_broadcast),
10662306a36Sopenharmony_ci	ICE_PF_STAT("tx_errors.nic", stats.eth.tx_errors),
10762306a36Sopenharmony_ci	ICE_PF_STAT("tx_timeout.nic", tx_timeout_count),
10862306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_64.nic", stats.rx_size_64),
10962306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_64.nic", stats.tx_size_64),
11062306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_127.nic", stats.rx_size_127),
11162306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_127.nic", stats.tx_size_127),
11262306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_255.nic", stats.rx_size_255),
11362306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_255.nic", stats.tx_size_255),
11462306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_511.nic", stats.rx_size_511),
11562306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_511.nic", stats.tx_size_511),
11662306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_1023.nic", stats.rx_size_1023),
11762306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_1023.nic", stats.tx_size_1023),
11862306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_1522.nic", stats.rx_size_1522),
11962306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_1522.nic", stats.tx_size_1522),
12062306a36Sopenharmony_ci	ICE_PF_STAT("rx_size_big.nic", stats.rx_size_big),
12162306a36Sopenharmony_ci	ICE_PF_STAT("tx_size_big.nic", stats.tx_size_big),
12262306a36Sopenharmony_ci	ICE_PF_STAT("link_xon_rx.nic", stats.link_xon_rx),
12362306a36Sopenharmony_ci	ICE_PF_STAT("link_xon_tx.nic", stats.link_xon_tx),
12462306a36Sopenharmony_ci	ICE_PF_STAT("link_xoff_rx.nic", stats.link_xoff_rx),
12562306a36Sopenharmony_ci	ICE_PF_STAT("link_xoff_tx.nic", stats.link_xoff_tx),
12662306a36Sopenharmony_ci	ICE_PF_STAT("tx_dropped_link_down.nic", stats.tx_dropped_link_down),
12762306a36Sopenharmony_ci	ICE_PF_STAT("rx_undersize.nic", stats.rx_undersize),
12862306a36Sopenharmony_ci	ICE_PF_STAT("rx_fragments.nic", stats.rx_fragments),
12962306a36Sopenharmony_ci	ICE_PF_STAT("rx_oversize.nic", stats.rx_oversize),
13062306a36Sopenharmony_ci	ICE_PF_STAT("rx_jabber.nic", stats.rx_jabber),
13162306a36Sopenharmony_ci	ICE_PF_STAT("rx_csum_bad.nic", hw_csum_rx_error),
13262306a36Sopenharmony_ci	ICE_PF_STAT("rx_length_errors.nic", stats.rx_len_errors),
13362306a36Sopenharmony_ci	ICE_PF_STAT("rx_dropped.nic", stats.eth.rx_discards),
13462306a36Sopenharmony_ci	ICE_PF_STAT("rx_crc_errors.nic", stats.crc_errors),
13562306a36Sopenharmony_ci	ICE_PF_STAT("illegal_bytes.nic", stats.illegal_bytes),
13662306a36Sopenharmony_ci	ICE_PF_STAT("mac_local_faults.nic", stats.mac_local_faults),
13762306a36Sopenharmony_ci	ICE_PF_STAT("mac_remote_faults.nic", stats.mac_remote_faults),
13862306a36Sopenharmony_ci	ICE_PF_STAT("fdir_sb_match.nic", stats.fd_sb_match),
13962306a36Sopenharmony_ci	ICE_PF_STAT("fdir_sb_status.nic", stats.fd_sb_status),
14062306a36Sopenharmony_ci	ICE_PF_STAT("tx_hwtstamp_skipped", ptp.tx_hwtstamp_skipped),
14162306a36Sopenharmony_ci	ICE_PF_STAT("tx_hwtstamp_timeouts", ptp.tx_hwtstamp_timeouts),
14262306a36Sopenharmony_ci	ICE_PF_STAT("tx_hwtstamp_flushed", ptp.tx_hwtstamp_flushed),
14362306a36Sopenharmony_ci	ICE_PF_STAT("tx_hwtstamp_discarded", ptp.tx_hwtstamp_discarded),
14462306a36Sopenharmony_ci	ICE_PF_STAT("late_cached_phc_updates", ptp.late_cached_phc_updates),
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic const u32 ice_regs_dump_list[] = {
14862306a36Sopenharmony_ci	PFGEN_STATE,
14962306a36Sopenharmony_ci	PRTGEN_STATUS,
15062306a36Sopenharmony_ci	QRX_CTRL(0),
15162306a36Sopenharmony_ci	QINT_TQCTL(0),
15262306a36Sopenharmony_ci	QINT_RQCTL(0),
15362306a36Sopenharmony_ci	PFINT_OICR_ENA,
15462306a36Sopenharmony_ci	QRX_ITR(0),
15562306a36Sopenharmony_ci#define GLDCB_TLPM_PCI_DM			0x000A0180
15662306a36Sopenharmony_ci	GLDCB_TLPM_PCI_DM,
15762306a36Sopenharmony_ci#define GLDCB_TLPM_TC2PFC			0x000A0194
15862306a36Sopenharmony_ci	GLDCB_TLPM_TC2PFC,
15962306a36Sopenharmony_ci#define TCDCB_TLPM_WAIT_DM(_i)			(0x000A0080 + ((_i) * 4))
16062306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(0),
16162306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(1),
16262306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(2),
16362306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(3),
16462306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(4),
16562306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(5),
16662306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(6),
16762306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(7),
16862306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(8),
16962306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(9),
17062306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(10),
17162306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(11),
17262306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(12),
17362306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(13),
17462306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(14),
17562306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(15),
17662306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(16),
17762306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(17),
17862306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(18),
17962306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(19),
18062306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(20),
18162306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(21),
18262306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(22),
18362306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(23),
18462306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(24),
18562306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(25),
18662306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(26),
18762306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(27),
18862306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(28),
18962306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(29),
19062306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(30),
19162306a36Sopenharmony_ci	TCDCB_TLPM_WAIT_DM(31),
19262306a36Sopenharmony_ci#define GLPCI_WATMK_CLNT_PIPEMON		0x000BFD90
19362306a36Sopenharmony_ci	GLPCI_WATMK_CLNT_PIPEMON,
19462306a36Sopenharmony_ci#define GLPCI_CUR_CLNT_COMMON			0x000BFD84
19562306a36Sopenharmony_ci	GLPCI_CUR_CLNT_COMMON,
19662306a36Sopenharmony_ci#define GLPCI_CUR_CLNT_PIPEMON			0x000BFD88
19762306a36Sopenharmony_ci	GLPCI_CUR_CLNT_PIPEMON,
19862306a36Sopenharmony_ci#define GLPCI_PCIERR				0x0009DEB0
19962306a36Sopenharmony_ci	GLPCI_PCIERR,
20062306a36Sopenharmony_ci#define GLPSM_DEBUG_CTL_STATUS			0x000B0600
20162306a36Sopenharmony_ci	GLPSM_DEBUG_CTL_STATUS,
20262306a36Sopenharmony_ci#define GLPSM0_DEBUG_FIFO_OVERFLOW_DETECT	0x000B0680
20362306a36Sopenharmony_ci	GLPSM0_DEBUG_FIFO_OVERFLOW_DETECT,
20462306a36Sopenharmony_ci#define GLPSM0_DEBUG_FIFO_UNDERFLOW_DETECT	0x000B0684
20562306a36Sopenharmony_ci	GLPSM0_DEBUG_FIFO_UNDERFLOW_DETECT,
20662306a36Sopenharmony_ci#define GLPSM0_DEBUG_DT_OUT_OF_WINDOW		0x000B0688
20762306a36Sopenharmony_ci	GLPSM0_DEBUG_DT_OUT_OF_WINDOW,
20862306a36Sopenharmony_ci#define GLPSM0_DEBUG_INTF_HW_ERROR_DETECT	0x000B069C
20962306a36Sopenharmony_ci	GLPSM0_DEBUG_INTF_HW_ERROR_DETECT,
21062306a36Sopenharmony_ci#define GLPSM0_DEBUG_MISC_HW_ERROR_DETECT	0x000B06A0
21162306a36Sopenharmony_ci	GLPSM0_DEBUG_MISC_HW_ERROR_DETECT,
21262306a36Sopenharmony_ci#define GLPSM1_DEBUG_FIFO_OVERFLOW_DETECT	0x000B0E80
21362306a36Sopenharmony_ci	GLPSM1_DEBUG_FIFO_OVERFLOW_DETECT,
21462306a36Sopenharmony_ci#define GLPSM1_DEBUG_FIFO_UNDERFLOW_DETECT	0x000B0E84
21562306a36Sopenharmony_ci	GLPSM1_DEBUG_FIFO_UNDERFLOW_DETECT,
21662306a36Sopenharmony_ci#define GLPSM1_DEBUG_SRL_FIFO_OVERFLOW_DETECT	0x000B0E88
21762306a36Sopenharmony_ci	GLPSM1_DEBUG_SRL_FIFO_OVERFLOW_DETECT,
21862306a36Sopenharmony_ci#define GLPSM1_DEBUG_SRL_FIFO_UNDERFLOW_DETECT  0x000B0E8C
21962306a36Sopenharmony_ci	GLPSM1_DEBUG_SRL_FIFO_UNDERFLOW_DETECT,
22062306a36Sopenharmony_ci#define GLPSM1_DEBUG_MISC_HW_ERROR_DETECT       0x000B0E90
22162306a36Sopenharmony_ci	GLPSM1_DEBUG_MISC_HW_ERROR_DETECT,
22262306a36Sopenharmony_ci#define GLPSM2_DEBUG_FIFO_OVERFLOW_DETECT       0x000B1680
22362306a36Sopenharmony_ci	GLPSM2_DEBUG_FIFO_OVERFLOW_DETECT,
22462306a36Sopenharmony_ci#define GLPSM2_DEBUG_FIFO_UNDERFLOW_DETECT      0x000B1684
22562306a36Sopenharmony_ci	GLPSM2_DEBUG_FIFO_UNDERFLOW_DETECT,
22662306a36Sopenharmony_ci#define GLPSM2_DEBUG_MISC_HW_ERROR_DETECT       0x000B1688
22762306a36Sopenharmony_ci	GLPSM2_DEBUG_MISC_HW_ERROR_DETECT,
22862306a36Sopenharmony_ci#define GLTDPU_TCLAN_COMP_BOB(_i)               (0x00049ADC + ((_i) * 4))
22962306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(1),
23062306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(2),
23162306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(3),
23262306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(4),
23362306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(5),
23462306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(6),
23562306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(7),
23662306a36Sopenharmony_ci	GLTDPU_TCLAN_COMP_BOB(8),
23762306a36Sopenharmony_ci#define GLTDPU_TCB_CMD_BOB(_i)                  (0x0004975C + ((_i) * 4))
23862306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(1),
23962306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(2),
24062306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(3),
24162306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(4),
24262306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(5),
24362306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(6),
24462306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(7),
24562306a36Sopenharmony_ci	GLTDPU_TCB_CMD_BOB(8),
24662306a36Sopenharmony_ci#define GLTDPU_PSM_UPDATE_BOB(_i)               (0x00049B5C + ((_i) * 4))
24762306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(1),
24862306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(2),
24962306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(3),
25062306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(4),
25162306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(5),
25262306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(6),
25362306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(7),
25462306a36Sopenharmony_ci	GLTDPU_PSM_UPDATE_BOB(8),
25562306a36Sopenharmony_ci#define GLTCB_CMD_IN_BOB(_i)                    (0x000AE288 + ((_i) * 4))
25662306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(1),
25762306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(2),
25862306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(3),
25962306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(4),
26062306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(5),
26162306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(6),
26262306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(7),
26362306a36Sopenharmony_ci	GLTCB_CMD_IN_BOB(8),
26462306a36Sopenharmony_ci#define GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(_i)   (0x000FC148 + ((_i) * 4))
26562306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(1),
26662306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(2),
26762306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(3),
26862306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(4),
26962306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(5),
27062306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(6),
27162306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(7),
27262306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_FBK_BOB_CTL(8),
27362306a36Sopenharmony_ci#define GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(_i) (0x000FC248 + ((_i) * 4))
27462306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(1),
27562306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(2),
27662306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(3),
27762306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(4),
27862306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(5),
27962306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(6),
28062306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(7),
28162306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_SCHED_BOB_CTL(8),
28262306a36Sopenharmony_ci#define GLLAN_TCLAN_CACHE_CTL_BOB_CTL(_i)       (0x000FC1C8 + ((_i) * 4))
28362306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(1),
28462306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(2),
28562306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(3),
28662306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(4),
28762306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(5),
28862306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(6),
28962306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(7),
29062306a36Sopenharmony_ci	GLLAN_TCLAN_CACHE_CTL_BOB_CTL(8),
29162306a36Sopenharmony_ci#define GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(_i)  (0x000FC188 + ((_i) * 4))
29262306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(1),
29362306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(2),
29462306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(3),
29562306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(4),
29662306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(5),
29762306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(6),
29862306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(7),
29962306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PROC_BOB_CTL(8),
30062306a36Sopenharmony_ci#define GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(_i) (0x000FC288 + ((_i) * 4))
30162306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(1),
30262306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(2),
30362306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(3),
30462306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(4),
30562306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(5),
30662306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(6),
30762306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(7),
30862306a36Sopenharmony_ci	GLLAN_TCLAN_FETCH_CTL_PCIE_RD_BOB_CTL(8),
30962306a36Sopenharmony_ci#define PRTDCB_TCUPM_REG_CM(_i)			(0x000BC360 + ((_i) * 4))
31062306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_CM(0),
31162306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_CM(1),
31262306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_CM(2),
31362306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_CM(3),
31462306a36Sopenharmony_ci#define PRTDCB_TCUPM_REG_DM(_i)			(0x000BC3A0 + ((_i) * 4))
31562306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_DM(0),
31662306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_DM(1),
31762306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_DM(2),
31862306a36Sopenharmony_ci	PRTDCB_TCUPM_REG_DM(3),
31962306a36Sopenharmony_ci#define PRTDCB_TLPM_REG_DM(_i)			(0x000A0000 + ((_i) * 4))
32062306a36Sopenharmony_ci	PRTDCB_TLPM_REG_DM(0),
32162306a36Sopenharmony_ci	PRTDCB_TLPM_REG_DM(1),
32262306a36Sopenharmony_ci	PRTDCB_TLPM_REG_DM(2),
32362306a36Sopenharmony_ci	PRTDCB_TLPM_REG_DM(3),
32462306a36Sopenharmony_ci};
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistruct ice_priv_flag {
32762306a36Sopenharmony_ci	char name[ETH_GSTRING_LEN];
32862306a36Sopenharmony_ci	u32 bitno;			/* bit position in pf->flags */
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci#define ICE_PRIV_FLAG(_name, _bitno) { \
33262306a36Sopenharmony_ci	.name = _name, \
33362306a36Sopenharmony_ci	.bitno = _bitno, \
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic const struct ice_priv_flag ice_gstrings_priv_flags[] = {
33762306a36Sopenharmony_ci	ICE_PRIV_FLAG("link-down-on-close", ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA),
33862306a36Sopenharmony_ci	ICE_PRIV_FLAG("fw-lldp-agent", ICE_FLAG_FW_LLDP_AGENT),
33962306a36Sopenharmony_ci	ICE_PRIV_FLAG("vf-true-promisc-support",
34062306a36Sopenharmony_ci		      ICE_FLAG_VF_TRUE_PROMISC_ENA),
34162306a36Sopenharmony_ci	ICE_PRIV_FLAG("mdd-auto-reset-vf", ICE_FLAG_MDD_AUTO_RESET_VF),
34262306a36Sopenharmony_ci	ICE_PRIV_FLAG("vf-vlan-pruning", ICE_FLAG_VF_VLAN_PRUNING),
34362306a36Sopenharmony_ci	ICE_PRIV_FLAG("legacy-rx", ICE_FLAG_LEGACY_RX),
34462306a36Sopenharmony_ci};
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci#define ICE_PRIV_FLAG_ARRAY_SIZE	ARRAY_SIZE(ice_gstrings_priv_flags)
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic void
34962306a36Sopenharmony_ci__ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo,
35062306a36Sopenharmony_ci		  struct ice_vsi *vsi)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
35362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
35462306a36Sopenharmony_ci	struct ice_orom_info *orom;
35562306a36Sopenharmony_ci	struct ice_nvm_info *nvm;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	nvm = &hw->flash.nvm;
35862306a36Sopenharmony_ci	orom = &hw->flash.orom;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* Display NVM version (from which the firmware version can be
36362306a36Sopenharmony_ci	 * determined) which contains more pertinent information.
36462306a36Sopenharmony_ci	 */
36562306a36Sopenharmony_ci	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
36662306a36Sopenharmony_ci		 "%x.%02x 0x%x %d.%d.%d", nvm->major, nvm->minor,
36762306a36Sopenharmony_ci		 nvm->eetrack, orom->major, orom->build, orom->patch);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, pci_name(pf->pdev),
37062306a36Sopenharmony_ci		sizeof(drvinfo->bus_info));
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void
37462306a36Sopenharmony_ciice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	__ice_get_drvinfo(netdev, drvinfo, np->vsi);
37962306a36Sopenharmony_ci	drvinfo->n_priv_flags = ICE_PRIV_FLAG_ARRAY_SIZE;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int ice_get_regs_len(struct net_device __always_unused *netdev)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	return sizeof(ice_regs_dump_list);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic void
38862306a36Sopenharmony_ciice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
39162306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
39262306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
39362306a36Sopenharmony_ci	u32 *regs_buf = (u32 *)p;
39462306a36Sopenharmony_ci	unsigned int i;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	regs->version = 1;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list); ++i)
39962306a36Sopenharmony_ci		regs_buf[i] = rd32(hw, ice_regs_dump_list[i]);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic u32 ice_get_msglevel(struct net_device *netdev)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
40562306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG
40862306a36Sopenharmony_ci	if (pf->hw.debug_mask)
40962306a36Sopenharmony_ci		netdev_info(netdev, "hw debug_mask: 0x%llX\n",
41062306a36Sopenharmony_ci			    pf->hw.debug_mask);
41162306a36Sopenharmony_ci#endif /* !CONFIG_DYNAMIC_DEBUG */
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return pf->msg_enable;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic void ice_set_msglevel(struct net_device *netdev, u32 data)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
41962306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG
42262306a36Sopenharmony_ci	if (ICE_DBG_USER & data)
42362306a36Sopenharmony_ci		pf->hw.debug_mask = data;
42462306a36Sopenharmony_ci	else
42562306a36Sopenharmony_ci		pf->msg_enable = data;
42662306a36Sopenharmony_ci#else
42762306a36Sopenharmony_ci	pf->msg_enable = data;
42862306a36Sopenharmony_ci#endif /* !CONFIG_DYNAMIC_DEBUG */
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int ice_get_eeprom_len(struct net_device *netdev)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
43462306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return (int)pf->hw.flash.flash_size;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic int
44062306a36Sopenharmony_ciice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
44162306a36Sopenharmony_ci	       u8 *bytes)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
44462306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
44562306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
44662306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
44762306a36Sopenharmony_ci	struct device *dev;
44862306a36Sopenharmony_ci	int ret;
44962306a36Sopenharmony_ci	u8 *buf;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
45462306a36Sopenharmony_ci	netdev_dbg(netdev, "GEEPROM cmd 0x%08x, offset 0x%08x, len 0x%08x\n",
45562306a36Sopenharmony_ci		   eeprom->cmd, eeprom->offset, eeprom->len);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	buf = kzalloc(eeprom->len, GFP_KERNEL);
45862306a36Sopenharmony_ci	if (!buf)
45962306a36Sopenharmony_ci		return -ENOMEM;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	ret = ice_acquire_nvm(hw, ICE_RES_READ);
46262306a36Sopenharmony_ci	if (ret) {
46362306a36Sopenharmony_ci		dev_err(dev, "ice_acquire_nvm failed, err %d aq_err %s\n",
46462306a36Sopenharmony_ci			ret, ice_aq_str(hw->adminq.sq_last_status));
46562306a36Sopenharmony_ci		goto out;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	ret = ice_read_flat_nvm(hw, eeprom->offset, &eeprom->len, buf,
46962306a36Sopenharmony_ci				false);
47062306a36Sopenharmony_ci	if (ret) {
47162306a36Sopenharmony_ci		dev_err(dev, "ice_read_flat_nvm failed, err %d aq_err %s\n",
47262306a36Sopenharmony_ci			ret, ice_aq_str(hw->adminq.sq_last_status));
47362306a36Sopenharmony_ci		goto release;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	memcpy(bytes, buf, eeprom->len);
47762306a36Sopenharmony_cirelease:
47862306a36Sopenharmony_ci	ice_release_nvm(hw);
47962306a36Sopenharmony_ciout:
48062306a36Sopenharmony_ci	kfree(buf);
48162306a36Sopenharmony_ci	return ret;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/**
48562306a36Sopenharmony_ci * ice_active_vfs - check if there are any active VFs
48662306a36Sopenharmony_ci * @pf: board private structure
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci * Returns true if an active VF is found, otherwise returns false
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic bool ice_active_vfs(struct ice_pf *pf)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	bool active = false;
49362306a36Sopenharmony_ci	struct ice_vf *vf;
49462306a36Sopenharmony_ci	unsigned int bkt;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	rcu_read_lock();
49762306a36Sopenharmony_ci	ice_for_each_vf_rcu(pf, bkt, vf) {
49862306a36Sopenharmony_ci		if (test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
49962306a36Sopenharmony_ci			active = true;
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	rcu_read_unlock();
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	return active;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/**
50962306a36Sopenharmony_ci * ice_link_test - perform a link test on a given net_device
51062306a36Sopenharmony_ci * @netdev: network interface device structure
51162306a36Sopenharmony_ci *
51262306a36Sopenharmony_ci * This function performs one of the self-tests required by ethtool.
51362306a36Sopenharmony_ci * Returns 0 on success, non-zero on failure.
51462306a36Sopenharmony_ci */
51562306a36Sopenharmony_cistatic u64 ice_link_test(struct net_device *netdev)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
51862306a36Sopenharmony_ci	bool link_up = false;
51962306a36Sopenharmony_ci	int status;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	netdev_info(netdev, "link test\n");
52262306a36Sopenharmony_ci	status = ice_get_link_status(np->vsi->port_info, &link_up);
52362306a36Sopenharmony_ci	if (status) {
52462306a36Sopenharmony_ci		netdev_err(netdev, "link query error, status = %d\n",
52562306a36Sopenharmony_ci			   status);
52662306a36Sopenharmony_ci		return 1;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (!link_up)
53062306a36Sopenharmony_ci		return 2;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	return 0;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci/**
53662306a36Sopenharmony_ci * ice_eeprom_test - perform an EEPROM test on a given net_device
53762306a36Sopenharmony_ci * @netdev: network interface device structure
53862306a36Sopenharmony_ci *
53962306a36Sopenharmony_ci * This function performs one of the self-tests required by ethtool.
54062306a36Sopenharmony_ci * Returns 0 on success, non-zero on failure.
54162306a36Sopenharmony_ci */
54262306a36Sopenharmony_cistatic u64 ice_eeprom_test(struct net_device *netdev)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
54562306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	netdev_info(netdev, "EEPROM test\n");
54862306a36Sopenharmony_ci	return !!(ice_nvm_validate_checksum(&pf->hw));
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci/**
55262306a36Sopenharmony_ci * ice_reg_pattern_test
55362306a36Sopenharmony_ci * @hw: pointer to the HW struct
55462306a36Sopenharmony_ci * @reg: reg to be tested
55562306a36Sopenharmony_ci * @mask: bits to be touched
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_cistatic int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct ice_pf *pf = (struct ice_pf *)hw->back;
56062306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
56162306a36Sopenharmony_ci	static const u32 patterns[] = {
56262306a36Sopenharmony_ci		0x5A5A5A5A, 0xA5A5A5A5,
56362306a36Sopenharmony_ci		0x00000000, 0xFFFFFFFF
56462306a36Sopenharmony_ci	};
56562306a36Sopenharmony_ci	u32 val, orig_val;
56662306a36Sopenharmony_ci	unsigned int i;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	orig_val = rd32(hw, reg);
56962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(patterns); ++i) {
57062306a36Sopenharmony_ci		u32 pattern = patterns[i] & mask;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci		wr32(hw, reg, pattern);
57362306a36Sopenharmony_ci		val = rd32(hw, reg);
57462306a36Sopenharmony_ci		if (val == pattern)
57562306a36Sopenharmony_ci			continue;
57662306a36Sopenharmony_ci		dev_err(dev, "%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n"
57762306a36Sopenharmony_ci			, __func__, reg, pattern, val);
57862306a36Sopenharmony_ci		return 1;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	wr32(hw, reg, orig_val);
58262306a36Sopenharmony_ci	val = rd32(hw, reg);
58362306a36Sopenharmony_ci	if (val != orig_val) {
58462306a36Sopenharmony_ci		dev_err(dev, "%s: reg restore test failed - reg 0x%08x orig 0x%08x val 0x%08x\n"
58562306a36Sopenharmony_ci			, __func__, reg, orig_val, val);
58662306a36Sopenharmony_ci		return 1;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/**
59362306a36Sopenharmony_ci * ice_reg_test - perform a register test on a given net_device
59462306a36Sopenharmony_ci * @netdev: network interface device structure
59562306a36Sopenharmony_ci *
59662306a36Sopenharmony_ci * This function performs one of the self-tests required by ethtool.
59762306a36Sopenharmony_ci * Returns 0 on success, non-zero on failure.
59862306a36Sopenharmony_ci */
59962306a36Sopenharmony_cistatic u64 ice_reg_test(struct net_device *netdev)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
60262306a36Sopenharmony_ci	struct ice_hw *hw = np->vsi->port_info->hw;
60362306a36Sopenharmony_ci	u32 int_elements = hw->func_caps.common_cap.num_msix_vectors ?
60462306a36Sopenharmony_ci		hw->func_caps.common_cap.num_msix_vectors - 1 : 1;
60562306a36Sopenharmony_ci	struct ice_diag_reg_test_info {
60662306a36Sopenharmony_ci		u32 address;
60762306a36Sopenharmony_ci		u32 mask;
60862306a36Sopenharmony_ci		u32 elem_num;
60962306a36Sopenharmony_ci		u32 elem_size;
61062306a36Sopenharmony_ci	} ice_reg_list[] = {
61162306a36Sopenharmony_ci		{GLINT_ITR(0, 0), 0x00000fff, int_elements,
61262306a36Sopenharmony_ci			GLINT_ITR(0, 1) - GLINT_ITR(0, 0)},
61362306a36Sopenharmony_ci		{GLINT_ITR(1, 0), 0x00000fff, int_elements,
61462306a36Sopenharmony_ci			GLINT_ITR(1, 1) - GLINT_ITR(1, 0)},
61562306a36Sopenharmony_ci		{GLINT_ITR(0, 0), 0x00000fff, int_elements,
61662306a36Sopenharmony_ci			GLINT_ITR(2, 1) - GLINT_ITR(2, 0)},
61762306a36Sopenharmony_ci		{GLINT_CTL, 0xffff0001, 1, 0}
61862306a36Sopenharmony_ci	};
61962306a36Sopenharmony_ci	unsigned int i;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	netdev_dbg(netdev, "Register test\n");
62262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ice_reg_list); ++i) {
62362306a36Sopenharmony_ci		u32 j;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		for (j = 0; j < ice_reg_list[i].elem_num; ++j) {
62662306a36Sopenharmony_ci			u32 mask = ice_reg_list[i].mask;
62762306a36Sopenharmony_ci			u32 reg = ice_reg_list[i].address +
62862306a36Sopenharmony_ci				(j * ice_reg_list[i].elem_size);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci			/* bail on failure (non-zero return) */
63162306a36Sopenharmony_ci			if (ice_reg_pattern_test(hw, reg, mask))
63262306a36Sopenharmony_ci				return 1;
63362306a36Sopenharmony_ci		}
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	return 0;
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/**
64062306a36Sopenharmony_ci * ice_lbtest_prepare_rings - configure Tx/Rx test rings
64162306a36Sopenharmony_ci * @vsi: pointer to the VSI structure
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci * Function configures rings of a VSI for loopback test without
64462306a36Sopenharmony_ci * enabling interrupts or informing the kernel about new queues.
64562306a36Sopenharmony_ci *
64662306a36Sopenharmony_ci * Returns 0 on success, negative on failure.
64762306a36Sopenharmony_ci */
64862306a36Sopenharmony_cistatic int ice_lbtest_prepare_rings(struct ice_vsi *vsi)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	int status;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	status = ice_vsi_setup_tx_rings(vsi);
65362306a36Sopenharmony_ci	if (status)
65462306a36Sopenharmony_ci		goto err_setup_tx_ring;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	status = ice_vsi_setup_rx_rings(vsi);
65762306a36Sopenharmony_ci	if (status)
65862306a36Sopenharmony_ci		goto err_setup_rx_ring;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	status = ice_vsi_cfg_lan(vsi);
66162306a36Sopenharmony_ci	if (status)
66262306a36Sopenharmony_ci		goto err_setup_rx_ring;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	status = ice_vsi_start_all_rx_rings(vsi);
66562306a36Sopenharmony_ci	if (status)
66662306a36Sopenharmony_ci		goto err_start_rx_ring;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return 0;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cierr_start_rx_ring:
67162306a36Sopenharmony_ci	ice_vsi_free_rx_rings(vsi);
67262306a36Sopenharmony_cierr_setup_rx_ring:
67362306a36Sopenharmony_ci	ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
67462306a36Sopenharmony_cierr_setup_tx_ring:
67562306a36Sopenharmony_ci	ice_vsi_free_tx_rings(vsi);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return status;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci/**
68162306a36Sopenharmony_ci * ice_lbtest_disable_rings - disable Tx/Rx test rings after loopback test
68262306a36Sopenharmony_ci * @vsi: pointer to the VSI structure
68362306a36Sopenharmony_ci *
68462306a36Sopenharmony_ci * Function stops and frees VSI rings after a loopback test.
68562306a36Sopenharmony_ci * Returns 0 on success, negative on failure.
68662306a36Sopenharmony_ci */
68762306a36Sopenharmony_cistatic int ice_lbtest_disable_rings(struct ice_vsi *vsi)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	int status;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	status = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
69262306a36Sopenharmony_ci	if (status)
69362306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed to stop Tx rings, VSI %d error %d\n",
69462306a36Sopenharmony_ci			   vsi->vsi_num, status);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	status = ice_vsi_stop_all_rx_rings(vsi);
69762306a36Sopenharmony_ci	if (status)
69862306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed to stop Rx rings, VSI %d error %d\n",
69962306a36Sopenharmony_ci			   vsi->vsi_num, status);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	ice_vsi_free_tx_rings(vsi);
70262306a36Sopenharmony_ci	ice_vsi_free_rx_rings(vsi);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	return status;
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci/**
70862306a36Sopenharmony_ci * ice_lbtest_create_frame - create test packet
70962306a36Sopenharmony_ci * @pf: pointer to the PF structure
71062306a36Sopenharmony_ci * @ret_data: allocated frame buffer
71162306a36Sopenharmony_ci * @size: size of the packet data
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * Function allocates a frame with a test pattern on specific offsets.
71462306a36Sopenharmony_ci * Returns 0 on success, non-zero on failure.
71562306a36Sopenharmony_ci */
71662306a36Sopenharmony_cistatic int ice_lbtest_create_frame(struct ice_pf *pf, u8 **ret_data, u16 size)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	u8 *data;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (!pf)
72162306a36Sopenharmony_ci		return -EINVAL;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	data = devm_kzalloc(ice_pf_to_dev(pf), size, GFP_KERNEL);
72462306a36Sopenharmony_ci	if (!data)
72562306a36Sopenharmony_ci		return -ENOMEM;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* Since the ethernet test frame should always be at least
72862306a36Sopenharmony_ci	 * 64 bytes long, fill some octets in the payload with test data.
72962306a36Sopenharmony_ci	 */
73062306a36Sopenharmony_ci	memset(data, 0xFF, size);
73162306a36Sopenharmony_ci	data[32] = 0xDE;
73262306a36Sopenharmony_ci	data[42] = 0xAD;
73362306a36Sopenharmony_ci	data[44] = 0xBE;
73462306a36Sopenharmony_ci	data[46] = 0xEF;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	*ret_data = data;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return 0;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci/**
74262306a36Sopenharmony_ci * ice_lbtest_check_frame - verify received loopback frame
74362306a36Sopenharmony_ci * @frame: pointer to the raw packet data
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * Function verifies received test frame with a pattern.
74662306a36Sopenharmony_ci * Returns true if frame matches the pattern, false otherwise.
74762306a36Sopenharmony_ci */
74862306a36Sopenharmony_cistatic bool ice_lbtest_check_frame(u8 *frame)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	/* Validate bytes of a frame under offsets chosen earlier */
75162306a36Sopenharmony_ci	if (frame[32] == 0xDE &&
75262306a36Sopenharmony_ci	    frame[42] == 0xAD &&
75362306a36Sopenharmony_ci	    frame[44] == 0xBE &&
75462306a36Sopenharmony_ci	    frame[46] == 0xEF &&
75562306a36Sopenharmony_ci	    frame[48] == 0xFF)
75662306a36Sopenharmony_ci		return true;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	return false;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci/**
76262306a36Sopenharmony_ci * ice_diag_send - send test frames to the test ring
76362306a36Sopenharmony_ci * @tx_ring: pointer to the transmit ring
76462306a36Sopenharmony_ci * @data: pointer to the raw packet data
76562306a36Sopenharmony_ci * @size: size of the packet to send
76662306a36Sopenharmony_ci *
76762306a36Sopenharmony_ci * Function sends loopback packets on a test Tx ring.
76862306a36Sopenharmony_ci */
76962306a36Sopenharmony_cistatic int ice_diag_send(struct ice_tx_ring *tx_ring, u8 *data, u16 size)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	struct ice_tx_desc *tx_desc;
77262306a36Sopenharmony_ci	struct ice_tx_buf *tx_buf;
77362306a36Sopenharmony_ci	dma_addr_t dma;
77462306a36Sopenharmony_ci	u64 td_cmd;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	tx_desc = ICE_TX_DESC(tx_ring, tx_ring->next_to_use);
77762306a36Sopenharmony_ci	tx_buf = &tx_ring->tx_buf[tx_ring->next_to_use];
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	dma = dma_map_single(tx_ring->dev, data, size, DMA_TO_DEVICE);
78062306a36Sopenharmony_ci	if (dma_mapping_error(tx_ring->dev, dma))
78162306a36Sopenharmony_ci		return -EINVAL;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	tx_desc->buf_addr = cpu_to_le64(dma);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	/* These flags are required for a descriptor to be pushed out */
78662306a36Sopenharmony_ci	td_cmd = (u64)(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS);
78762306a36Sopenharmony_ci	tx_desc->cmd_type_offset_bsz =
78862306a36Sopenharmony_ci		cpu_to_le64(ICE_TX_DESC_DTYPE_DATA |
78962306a36Sopenharmony_ci			    (td_cmd << ICE_TXD_QW1_CMD_S) |
79062306a36Sopenharmony_ci			    ((u64)0 << ICE_TXD_QW1_OFFSET_S) |
79162306a36Sopenharmony_ci			    ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) |
79262306a36Sopenharmony_ci			    ((u64)0 << ICE_TXD_QW1_L2TAG1_S));
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	tx_buf->next_to_watch = tx_desc;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* Force memory write to complete before letting h/w know
79762306a36Sopenharmony_ci	 * there are new descriptors to fetch.
79862306a36Sopenharmony_ci	 */
79962306a36Sopenharmony_ci	wmb();
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	tx_ring->next_to_use++;
80262306a36Sopenharmony_ci	if (tx_ring->next_to_use >= tx_ring->count)
80362306a36Sopenharmony_ci		tx_ring->next_to_use = 0;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	writel_relaxed(tx_ring->next_to_use, tx_ring->tail);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* Wait until the packets get transmitted to the receive queue. */
80862306a36Sopenharmony_ci	usleep_range(1000, 2000);
80962306a36Sopenharmony_ci	dma_unmap_single(tx_ring->dev, dma, size, DMA_TO_DEVICE);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return 0;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci#define ICE_LB_FRAME_SIZE 64
81562306a36Sopenharmony_ci/**
81662306a36Sopenharmony_ci * ice_lbtest_receive_frames - receive and verify test frames
81762306a36Sopenharmony_ci * @rx_ring: pointer to the receive ring
81862306a36Sopenharmony_ci *
81962306a36Sopenharmony_ci * Function receives loopback packets and verify their correctness.
82062306a36Sopenharmony_ci * Returns number of received valid frames.
82162306a36Sopenharmony_ci */
82262306a36Sopenharmony_cistatic int ice_lbtest_receive_frames(struct ice_rx_ring *rx_ring)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	struct ice_rx_buf *rx_buf;
82562306a36Sopenharmony_ci	int valid_frames, i;
82662306a36Sopenharmony_ci	u8 *received_buf;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	valid_frames = 0;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	for (i = 0; i < rx_ring->count; i++) {
83162306a36Sopenharmony_ci		union ice_32b_rx_flex_desc *rx_desc;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		rx_desc = ICE_RX_DESC(rx_ring, i);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		if (!(rx_desc->wb.status_error0 &
83662306a36Sopenharmony_ci		    (cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S)) |
83762306a36Sopenharmony_ci		     cpu_to_le16(BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S)))))
83862306a36Sopenharmony_ci			continue;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		rx_buf = &rx_ring->rx_buf[i];
84162306a36Sopenharmony_ci		received_buf = page_address(rx_buf->page) + rx_buf->page_offset;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		if (ice_lbtest_check_frame(received_buf))
84462306a36Sopenharmony_ci			valid_frames++;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return valid_frames;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci/**
85162306a36Sopenharmony_ci * ice_loopback_test - perform a loopback test on a given net_device
85262306a36Sopenharmony_ci * @netdev: network interface device structure
85362306a36Sopenharmony_ci *
85462306a36Sopenharmony_ci * This function performs one of the self-tests required by ethtool.
85562306a36Sopenharmony_ci * Returns 0 on success, non-zero on failure.
85662306a36Sopenharmony_ci */
85762306a36Sopenharmony_cistatic u64 ice_loopback_test(struct net_device *netdev)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
86062306a36Sopenharmony_ci	struct ice_vsi *orig_vsi = np->vsi, *test_vsi;
86162306a36Sopenharmony_ci	struct ice_pf *pf = orig_vsi->back;
86262306a36Sopenharmony_ci	u8 broadcast[ETH_ALEN], ret = 0;
86362306a36Sopenharmony_ci	int num_frames, valid_frames;
86462306a36Sopenharmony_ci	struct ice_tx_ring *tx_ring;
86562306a36Sopenharmony_ci	struct ice_rx_ring *rx_ring;
86662306a36Sopenharmony_ci	struct device *dev;
86762306a36Sopenharmony_ci	u8 *tx_frame;
86862306a36Sopenharmony_ci	int i;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
87162306a36Sopenharmony_ci	netdev_info(netdev, "loopback test\n");
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	test_vsi = ice_lb_vsi_setup(pf, pf->hw.port_info);
87462306a36Sopenharmony_ci	if (!test_vsi) {
87562306a36Sopenharmony_ci		netdev_err(netdev, "Failed to create a VSI for the loopback test\n");
87662306a36Sopenharmony_ci		return 1;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	test_vsi->netdev = netdev;
88062306a36Sopenharmony_ci	tx_ring = test_vsi->tx_rings[0];
88162306a36Sopenharmony_ci	rx_ring = test_vsi->rx_rings[0];
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (ice_lbtest_prepare_rings(test_vsi)) {
88462306a36Sopenharmony_ci		ret = 2;
88562306a36Sopenharmony_ci		goto lbtest_vsi_close;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	if (ice_alloc_rx_bufs(rx_ring, rx_ring->count)) {
88962306a36Sopenharmony_ci		ret = 3;
89062306a36Sopenharmony_ci		goto lbtest_rings_dis;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* Enable MAC loopback in firmware */
89462306a36Sopenharmony_ci	if (ice_aq_set_mac_loopback(&pf->hw, true, NULL)) {
89562306a36Sopenharmony_ci		ret = 4;
89662306a36Sopenharmony_ci		goto lbtest_mac_dis;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/* Test VSI needs to receive broadcast packets */
90062306a36Sopenharmony_ci	eth_broadcast_addr(broadcast);
90162306a36Sopenharmony_ci	if (ice_fltr_add_mac(test_vsi, broadcast, ICE_FWD_TO_VSI)) {
90262306a36Sopenharmony_ci		ret = 5;
90362306a36Sopenharmony_ci		goto lbtest_mac_dis;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	if (ice_lbtest_create_frame(pf, &tx_frame, ICE_LB_FRAME_SIZE)) {
90762306a36Sopenharmony_ci		ret = 7;
90862306a36Sopenharmony_ci		goto remove_mac_filters;
90962306a36Sopenharmony_ci	}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	num_frames = min_t(int, tx_ring->count, 32);
91262306a36Sopenharmony_ci	for (i = 0; i < num_frames; i++) {
91362306a36Sopenharmony_ci		if (ice_diag_send(tx_ring, tx_frame, ICE_LB_FRAME_SIZE)) {
91462306a36Sopenharmony_ci			ret = 8;
91562306a36Sopenharmony_ci			goto lbtest_free_frame;
91662306a36Sopenharmony_ci		}
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	valid_frames = ice_lbtest_receive_frames(rx_ring);
92062306a36Sopenharmony_ci	if (!valid_frames)
92162306a36Sopenharmony_ci		ret = 9;
92262306a36Sopenharmony_ci	else if (valid_frames != num_frames)
92362306a36Sopenharmony_ci		ret = 10;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cilbtest_free_frame:
92662306a36Sopenharmony_ci	devm_kfree(dev, tx_frame);
92762306a36Sopenharmony_ciremove_mac_filters:
92862306a36Sopenharmony_ci	if (ice_fltr_remove_mac(test_vsi, broadcast, ICE_FWD_TO_VSI))
92962306a36Sopenharmony_ci		netdev_err(netdev, "Could not remove MAC filter for the test VSI\n");
93062306a36Sopenharmony_cilbtest_mac_dis:
93162306a36Sopenharmony_ci	/* Disable MAC loopback after the test is completed. */
93262306a36Sopenharmony_ci	if (ice_aq_set_mac_loopback(&pf->hw, false, NULL))
93362306a36Sopenharmony_ci		netdev_err(netdev, "Could not disable MAC loopback\n");
93462306a36Sopenharmony_cilbtest_rings_dis:
93562306a36Sopenharmony_ci	if (ice_lbtest_disable_rings(test_vsi))
93662306a36Sopenharmony_ci		netdev_err(netdev, "Could not disable test rings\n");
93762306a36Sopenharmony_cilbtest_vsi_close:
93862306a36Sopenharmony_ci	test_vsi->netdev = NULL;
93962306a36Sopenharmony_ci	if (ice_vsi_release(test_vsi))
94062306a36Sopenharmony_ci		netdev_err(netdev, "Failed to remove the test VSI\n");
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return ret;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci/**
94662306a36Sopenharmony_ci * ice_intr_test - perform an interrupt test on a given net_device
94762306a36Sopenharmony_ci * @netdev: network interface device structure
94862306a36Sopenharmony_ci *
94962306a36Sopenharmony_ci * This function performs one of the self-tests required by ethtool.
95062306a36Sopenharmony_ci * Returns 0 on success, non-zero on failure.
95162306a36Sopenharmony_ci */
95262306a36Sopenharmony_cistatic u64 ice_intr_test(struct net_device *netdev)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
95562306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
95662306a36Sopenharmony_ci	u16 swic_old = pf->sw_int_count;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	netdev_info(netdev, "interrupt test\n");
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_irq.index),
96162306a36Sopenharmony_ci	     GLINT_DYN_CTL_SW_ITR_INDX_M |
96262306a36Sopenharmony_ci	     GLINT_DYN_CTL_INTENA_MSK_M |
96362306a36Sopenharmony_ci	     GLINT_DYN_CTL_SWINT_TRIG_M);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	usleep_range(1000, 2000);
96662306a36Sopenharmony_ci	return (swic_old == pf->sw_int_count);
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci/**
97062306a36Sopenharmony_ci * ice_self_test - handler function for performing a self-test by ethtool
97162306a36Sopenharmony_ci * @netdev: network interface device structure
97262306a36Sopenharmony_ci * @eth_test: ethtool_test structure
97362306a36Sopenharmony_ci * @data: required by ethtool.self_test
97462306a36Sopenharmony_ci *
97562306a36Sopenharmony_ci * This function is called after invoking 'ethtool -t devname' command where
97662306a36Sopenharmony_ci * devname is the name of the network device on which ethtool should operate.
97762306a36Sopenharmony_ci * It performs a set of self-tests to check if a device works properly.
97862306a36Sopenharmony_ci */
97962306a36Sopenharmony_cistatic void
98062306a36Sopenharmony_ciice_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
98162306a36Sopenharmony_ci	      u64 *data)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
98462306a36Sopenharmony_ci	bool if_running = netif_running(netdev);
98562306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
98662306a36Sopenharmony_ci	struct device *dev;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
99162306a36Sopenharmony_ci		netdev_info(netdev, "offline testing starting\n");
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		set_bit(ICE_TESTING, pf->state);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		if (ice_active_vfs(pf)) {
99662306a36Sopenharmony_ci			dev_warn(dev, "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n");
99762306a36Sopenharmony_ci			data[ICE_ETH_TEST_REG] = 1;
99862306a36Sopenharmony_ci			data[ICE_ETH_TEST_EEPROM] = 1;
99962306a36Sopenharmony_ci			data[ICE_ETH_TEST_INTR] = 1;
100062306a36Sopenharmony_ci			data[ICE_ETH_TEST_LOOP] = 1;
100162306a36Sopenharmony_ci			data[ICE_ETH_TEST_LINK] = 1;
100262306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
100362306a36Sopenharmony_ci			clear_bit(ICE_TESTING, pf->state);
100462306a36Sopenharmony_ci			goto skip_ol_tests;
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci		/* If the device is online then take it offline */
100762306a36Sopenharmony_ci		if (if_running)
100862306a36Sopenharmony_ci			/* indicate we're in test mode */
100962306a36Sopenharmony_ci			ice_stop(netdev);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci		data[ICE_ETH_TEST_LINK] = ice_link_test(netdev);
101262306a36Sopenharmony_ci		data[ICE_ETH_TEST_EEPROM] = ice_eeprom_test(netdev);
101362306a36Sopenharmony_ci		data[ICE_ETH_TEST_INTR] = ice_intr_test(netdev);
101462306a36Sopenharmony_ci		data[ICE_ETH_TEST_LOOP] = ice_loopback_test(netdev);
101562306a36Sopenharmony_ci		data[ICE_ETH_TEST_REG] = ice_reg_test(netdev);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci		if (data[ICE_ETH_TEST_LINK] ||
101862306a36Sopenharmony_ci		    data[ICE_ETH_TEST_EEPROM] ||
101962306a36Sopenharmony_ci		    data[ICE_ETH_TEST_LOOP] ||
102062306a36Sopenharmony_ci		    data[ICE_ETH_TEST_INTR] ||
102162306a36Sopenharmony_ci		    data[ICE_ETH_TEST_REG])
102262306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci		clear_bit(ICE_TESTING, pf->state);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		if (if_running) {
102762306a36Sopenharmony_ci			int status = ice_open(netdev);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci			if (status) {
103062306a36Sopenharmony_ci				dev_err(dev, "Could not open device %s, err %d\n",
103162306a36Sopenharmony_ci					pf->int_name, status);
103262306a36Sopenharmony_ci			}
103362306a36Sopenharmony_ci		}
103462306a36Sopenharmony_ci	} else {
103562306a36Sopenharmony_ci		/* Online tests */
103662306a36Sopenharmony_ci		netdev_info(netdev, "online testing starting\n");
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		data[ICE_ETH_TEST_LINK] = ice_link_test(netdev);
103962306a36Sopenharmony_ci		if (data[ICE_ETH_TEST_LINK])
104062306a36Sopenharmony_ci			eth_test->flags |= ETH_TEST_FL_FAILED;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci		/* Offline only tests, not run in online; pass by default */
104362306a36Sopenharmony_ci		data[ICE_ETH_TEST_REG] = 0;
104462306a36Sopenharmony_ci		data[ICE_ETH_TEST_EEPROM] = 0;
104562306a36Sopenharmony_ci		data[ICE_ETH_TEST_INTR] = 0;
104662306a36Sopenharmony_ci		data[ICE_ETH_TEST_LOOP] = 0;
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ciskip_ol_tests:
105062306a36Sopenharmony_ci	netdev_info(netdev, "testing finished\n");
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic void
105462306a36Sopenharmony_ci__ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data,
105562306a36Sopenharmony_ci		  struct ice_vsi *vsi)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	unsigned int i;
105862306a36Sopenharmony_ci	u8 *p = data;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	switch (stringset) {
106162306a36Sopenharmony_ci	case ETH_SS_STATS:
106262306a36Sopenharmony_ci		for (i = 0; i < ICE_VSI_STATS_LEN; i++)
106362306a36Sopenharmony_ci			ethtool_sprintf(&p,
106462306a36Sopenharmony_ci					ice_gstrings_vsi_stats[i].stat_string);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci		if (ice_is_port_repr_netdev(netdev))
106762306a36Sopenharmony_ci			return;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		ice_for_each_alloc_txq(vsi, i) {
107062306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_queue_%u_packets", i);
107162306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
107262306a36Sopenharmony_ci		}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci		ice_for_each_alloc_rxq(vsi, i) {
107562306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_queue_%u_packets", i);
107662306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_queue_%u_bytes", i);
107762306a36Sopenharmony_ci		}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		if (vsi->type != ICE_VSI_PF)
108062306a36Sopenharmony_ci			return;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci		for (i = 0; i < ICE_PF_STATS_LEN; i++)
108362306a36Sopenharmony_ci			ethtool_sprintf(&p,
108462306a36Sopenharmony_ci					ice_gstrings_pf_stats[i].stat_string);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci		for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) {
108762306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_priority_%u_xon.nic", i);
108862306a36Sopenharmony_ci			ethtool_sprintf(&p, "tx_priority_%u_xoff.nic", i);
108962306a36Sopenharmony_ci		}
109062306a36Sopenharmony_ci		for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) {
109162306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_priority_%u_xon.nic", i);
109262306a36Sopenharmony_ci			ethtool_sprintf(&p, "rx_priority_%u_xoff.nic", i);
109362306a36Sopenharmony_ci		}
109462306a36Sopenharmony_ci		break;
109562306a36Sopenharmony_ci	case ETH_SS_TEST:
109662306a36Sopenharmony_ci		memcpy(data, ice_gstrings_test, ICE_TEST_LEN * ETH_GSTRING_LEN);
109762306a36Sopenharmony_ci		break;
109862306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
109962306a36Sopenharmony_ci		for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++)
110062306a36Sopenharmony_ci			ethtool_sprintf(&p, ice_gstrings_priv_flags[i].name);
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci	default:
110362306a36Sopenharmony_ci		break;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic void ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	__ice_get_strings(netdev, stringset, data, np->vsi);
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic int
111562306a36Sopenharmony_ciice_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
111862306a36Sopenharmony_ci	bool led_active;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	switch (state) {
112162306a36Sopenharmony_ci	case ETHTOOL_ID_ACTIVE:
112262306a36Sopenharmony_ci		led_active = true;
112362306a36Sopenharmony_ci		break;
112462306a36Sopenharmony_ci	case ETHTOOL_ID_INACTIVE:
112562306a36Sopenharmony_ci		led_active = false;
112662306a36Sopenharmony_ci		break;
112762306a36Sopenharmony_ci	default:
112862306a36Sopenharmony_ci		return -EINVAL;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (ice_aq_set_port_id_led(np->vsi->port_info, !led_active, NULL))
113262306a36Sopenharmony_ci		return -EIO;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	return 0;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci/**
113862306a36Sopenharmony_ci * ice_set_fec_cfg - Set link FEC options
113962306a36Sopenharmony_ci * @netdev: network interface device structure
114062306a36Sopenharmony_ci * @req_fec: FEC mode to configure
114162306a36Sopenharmony_ci */
114262306a36Sopenharmony_cistatic int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
114562306a36Sopenharmony_ci	struct ice_aqc_set_phy_cfg_data config = { 0 };
114662306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
114762306a36Sopenharmony_ci	struct ice_port_info *pi;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	pi = vsi->port_info;
115062306a36Sopenharmony_ci	if (!pi)
115162306a36Sopenharmony_ci		return -EOPNOTSUPP;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* Changing the FEC parameters is not supported if not the PF VSI */
115462306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF) {
115562306a36Sopenharmony_ci		netdev_info(netdev, "Changing FEC parameters only supported for PF VSI\n");
115662306a36Sopenharmony_ci		return -EOPNOTSUPP;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	/* Proceed only if requesting different FEC mode */
116062306a36Sopenharmony_ci	if (pi->phy.curr_user_fec_req == req_fec)
116162306a36Sopenharmony_ci		return 0;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	/* Copy the current user PHY configuration. The current user PHY
116462306a36Sopenharmony_ci	 * configuration is initialized during probe from PHY capabilities
116562306a36Sopenharmony_ci	 * software mode, and updated on set PHY configuration.
116662306a36Sopenharmony_ci	 */
116762306a36Sopenharmony_ci	memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config));
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	ice_cfg_phy_fec(pi, &config, req_fec);
117062306a36Sopenharmony_ci	config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (ice_aq_set_phy_cfg(pi->hw, pi, &config, NULL))
117362306a36Sopenharmony_ci		return -EAGAIN;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* Save requested FEC config */
117662306a36Sopenharmony_ci	pi->phy.curr_user_fec_req = req_fec;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	return 0;
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci/**
118262306a36Sopenharmony_ci * ice_set_fecparam - Set FEC link options
118362306a36Sopenharmony_ci * @netdev: network interface device structure
118462306a36Sopenharmony_ci * @fecparam: Ethtool structure to retrieve FEC parameters
118562306a36Sopenharmony_ci */
118662306a36Sopenharmony_cistatic int
118762306a36Sopenharmony_ciice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
119062306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
119162306a36Sopenharmony_ci	enum ice_fec_mode fec;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	switch (fecparam->fec) {
119462306a36Sopenharmony_ci	case ETHTOOL_FEC_AUTO:
119562306a36Sopenharmony_ci		fec = ICE_FEC_AUTO;
119662306a36Sopenharmony_ci		break;
119762306a36Sopenharmony_ci	case ETHTOOL_FEC_RS:
119862306a36Sopenharmony_ci		fec = ICE_FEC_RS;
119962306a36Sopenharmony_ci		break;
120062306a36Sopenharmony_ci	case ETHTOOL_FEC_BASER:
120162306a36Sopenharmony_ci		fec = ICE_FEC_BASER;
120262306a36Sopenharmony_ci		break;
120362306a36Sopenharmony_ci	case ETHTOOL_FEC_OFF:
120462306a36Sopenharmony_ci	case ETHTOOL_FEC_NONE:
120562306a36Sopenharmony_ci		fec = ICE_FEC_NONE;
120662306a36Sopenharmony_ci		break;
120762306a36Sopenharmony_ci	default:
120862306a36Sopenharmony_ci		dev_warn(ice_pf_to_dev(vsi->back), "Unsupported FEC mode: %d\n",
120962306a36Sopenharmony_ci			 fecparam->fec);
121062306a36Sopenharmony_ci		return -EINVAL;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return ice_set_fec_cfg(netdev, fec);
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci/**
121762306a36Sopenharmony_ci * ice_get_fecparam - Get link FEC options
121862306a36Sopenharmony_ci * @netdev: network interface device structure
121962306a36Sopenharmony_ci * @fecparam: Ethtool structure to retrieve FEC parameters
122062306a36Sopenharmony_ci */
122162306a36Sopenharmony_cistatic int
122262306a36Sopenharmony_ciice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
122562306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *caps;
122662306a36Sopenharmony_ci	struct ice_link_status *link_info;
122762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
122862306a36Sopenharmony_ci	struct ice_port_info *pi;
122962306a36Sopenharmony_ci	int err;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	pi = vsi->port_info;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if (!pi)
123462306a36Sopenharmony_ci		return -EOPNOTSUPP;
123562306a36Sopenharmony_ci	link_info = &pi->phy.link_info;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	/* Set FEC mode based on negotiated link info */
123862306a36Sopenharmony_ci	switch (link_info->fec_info) {
123962306a36Sopenharmony_ci	case ICE_AQ_LINK_25G_KR_FEC_EN:
124062306a36Sopenharmony_ci		fecparam->active_fec = ETHTOOL_FEC_BASER;
124162306a36Sopenharmony_ci		break;
124262306a36Sopenharmony_ci	case ICE_AQ_LINK_25G_RS_528_FEC_EN:
124362306a36Sopenharmony_ci	case ICE_AQ_LINK_25G_RS_544_FEC_EN:
124462306a36Sopenharmony_ci		fecparam->active_fec = ETHTOOL_FEC_RS;
124562306a36Sopenharmony_ci		break;
124662306a36Sopenharmony_ci	default:
124762306a36Sopenharmony_ci		fecparam->active_fec = ETHTOOL_FEC_OFF;
124862306a36Sopenharmony_ci		break;
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	caps = kzalloc(sizeof(*caps), GFP_KERNEL);
125262306a36Sopenharmony_ci	if (!caps)
125362306a36Sopenharmony_ci		return -ENOMEM;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA,
125662306a36Sopenharmony_ci				  caps, NULL);
125762306a36Sopenharmony_ci	if (err)
125862306a36Sopenharmony_ci		goto done;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/* Set supported/configured FEC modes based on PHY capability */
126162306a36Sopenharmony_ci	if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC)
126262306a36Sopenharmony_ci		fecparam->fec |= ETHTOOL_FEC_AUTO;
126362306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
126462306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
126562306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN ||
126662306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
126762306a36Sopenharmony_ci		fecparam->fec |= ETHTOOL_FEC_BASER;
126862306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
126962306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ ||
127062306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
127162306a36Sopenharmony_ci		fecparam->fec |= ETHTOOL_FEC_RS;
127262306a36Sopenharmony_ci	if (caps->link_fec_options == 0)
127362306a36Sopenharmony_ci		fecparam->fec |= ETHTOOL_FEC_OFF;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cidone:
127662306a36Sopenharmony_ci	kfree(caps);
127762306a36Sopenharmony_ci	return err;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci/**
128162306a36Sopenharmony_ci * ice_nway_reset - restart autonegotiation
128262306a36Sopenharmony_ci * @netdev: network interface device structure
128362306a36Sopenharmony_ci */
128462306a36Sopenharmony_cistatic int ice_nway_reset(struct net_device *netdev)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
128762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
128862306a36Sopenharmony_ci	int err;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* If VSI state is up, then restart autoneg with link up */
129162306a36Sopenharmony_ci	if (!test_bit(ICE_DOWN, vsi->back->state))
129262306a36Sopenharmony_ci		err = ice_set_link(vsi, true);
129362306a36Sopenharmony_ci	else
129462306a36Sopenharmony_ci		err = ice_set_link(vsi, false);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return err;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci/**
130062306a36Sopenharmony_ci * ice_get_priv_flags - report device private flags
130162306a36Sopenharmony_ci * @netdev: network interface device structure
130262306a36Sopenharmony_ci *
130362306a36Sopenharmony_ci * The get string set count and the string set should be matched for each
130462306a36Sopenharmony_ci * flag returned.  Add new strings for each flag to the ice_gstrings_priv_flags
130562306a36Sopenharmony_ci * array.
130662306a36Sopenharmony_ci *
130762306a36Sopenharmony_ci * Returns a u32 bitmap of flags.
130862306a36Sopenharmony_ci */
130962306a36Sopenharmony_cistatic u32 ice_get_priv_flags(struct net_device *netdev)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
131262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
131362306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
131462306a36Sopenharmony_ci	u32 i, ret_flags = 0;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) {
131762306a36Sopenharmony_ci		const struct ice_priv_flag *priv_flag;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		priv_flag = &ice_gstrings_priv_flags[i];
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci		if (test_bit(priv_flag->bitno, pf->flags))
132262306a36Sopenharmony_ci			ret_flags |= BIT(i);
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	return ret_flags;
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci/**
132962306a36Sopenharmony_ci * ice_set_priv_flags - set private flags
133062306a36Sopenharmony_ci * @netdev: network interface device structure
133162306a36Sopenharmony_ci * @flags: bit flags to be set
133262306a36Sopenharmony_ci */
133362306a36Sopenharmony_cistatic int ice_set_priv_flags(struct net_device *netdev, u32 flags)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
133662306a36Sopenharmony_ci	DECLARE_BITMAP(change_flags, ICE_PF_FLAGS_NBITS);
133762306a36Sopenharmony_ci	DECLARE_BITMAP(orig_flags, ICE_PF_FLAGS_NBITS);
133862306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
133962306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
134062306a36Sopenharmony_ci	struct device *dev;
134162306a36Sopenharmony_ci	int ret = 0;
134262306a36Sopenharmony_ci	u32 i;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (flags > BIT(ICE_PRIV_FLAG_ARRAY_SIZE))
134562306a36Sopenharmony_ci		return -EINVAL;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
134862306a36Sopenharmony_ci	set_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	bitmap_copy(orig_flags, pf->flags, ICE_PF_FLAGS_NBITS);
135162306a36Sopenharmony_ci	for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) {
135262306a36Sopenharmony_ci		const struct ice_priv_flag *priv_flag;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci		priv_flag = &ice_gstrings_priv_flags[i];
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci		if (flags & BIT(i))
135762306a36Sopenharmony_ci			set_bit(priv_flag->bitno, pf->flags);
135862306a36Sopenharmony_ci		else
135962306a36Sopenharmony_ci			clear_bit(priv_flag->bitno, pf->flags);
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	bitmap_xor(change_flags, pf->flags, orig_flags, ICE_PF_FLAGS_NBITS);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	/* Do not allow change to link-down-on-close when Total Port Shutdown
136562306a36Sopenharmony_ci	 * is enabled.
136662306a36Sopenharmony_ci	 */
136762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, change_flags) &&
136862306a36Sopenharmony_ci	    test_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) {
136962306a36Sopenharmony_ci		dev_err(dev, "Setting link-down-on-close not supported on this port\n");
137062306a36Sopenharmony_ci		set_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags);
137162306a36Sopenharmony_ci		ret = -EINVAL;
137262306a36Sopenharmony_ci		goto ethtool_exit;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_FW_LLDP_AGENT, change_flags)) {
137662306a36Sopenharmony_ci		if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) {
137762306a36Sopenharmony_ci			int status;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci			/* Disable FW LLDP engine */
138062306a36Sopenharmony_ci			status = ice_cfg_lldp_mib_change(&pf->hw, false);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci			/* If unregistering for LLDP events fails, this is
138362306a36Sopenharmony_ci			 * not an error state, as there shouldn't be any
138462306a36Sopenharmony_ci			 * events to respond to.
138562306a36Sopenharmony_ci			 */
138662306a36Sopenharmony_ci			if (status)
138762306a36Sopenharmony_ci				dev_info(dev, "Failed to unreg for LLDP events\n");
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci			/* The AQ call to stop the FW LLDP agent will generate
139062306a36Sopenharmony_ci			 * an error if the agent is already stopped.
139162306a36Sopenharmony_ci			 */
139262306a36Sopenharmony_ci			status = ice_aq_stop_lldp(&pf->hw, true, true, NULL);
139362306a36Sopenharmony_ci			if (status)
139462306a36Sopenharmony_ci				dev_warn(dev, "Fail to stop LLDP agent\n");
139562306a36Sopenharmony_ci			/* Use case for having the FW LLDP agent stopped
139662306a36Sopenharmony_ci			 * will likely not need DCB, so failure to init is
139762306a36Sopenharmony_ci			 * not a concern of ethtool
139862306a36Sopenharmony_ci			 */
139962306a36Sopenharmony_ci			status = ice_init_pf_dcb(pf, true);
140062306a36Sopenharmony_ci			if (status)
140162306a36Sopenharmony_ci				dev_warn(dev, "Fail to init DCB\n");
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci			pf->dcbx_cap &= ~DCB_CAP_DCBX_LLD_MANAGED;
140462306a36Sopenharmony_ci			pf->dcbx_cap |= DCB_CAP_DCBX_HOST;
140562306a36Sopenharmony_ci		} else {
140662306a36Sopenharmony_ci			bool dcbx_agent_status;
140762306a36Sopenharmony_ci			int status;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci			if (ice_get_pfc_mode(pf) == ICE_QOS_MODE_DSCP) {
141062306a36Sopenharmony_ci				clear_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags);
141162306a36Sopenharmony_ci				dev_err(dev, "QoS in L3 DSCP mode, FW Agent not allowed to start\n");
141262306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
141362306a36Sopenharmony_ci				goto ethtool_exit;
141462306a36Sopenharmony_ci			}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci			/* Remove rule to direct LLDP packets to default VSI.
141762306a36Sopenharmony_ci			 * The FW LLDP engine will now be consuming them.
141862306a36Sopenharmony_ci			 */
141962306a36Sopenharmony_ci			ice_cfg_sw_lldp(vsi, false, false);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci			/* AQ command to start FW LLDP agent will return an
142262306a36Sopenharmony_ci			 * error if the agent is already started
142362306a36Sopenharmony_ci			 */
142462306a36Sopenharmony_ci			status = ice_aq_start_lldp(&pf->hw, true, NULL);
142562306a36Sopenharmony_ci			if (status)
142662306a36Sopenharmony_ci				dev_warn(dev, "Fail to start LLDP Agent\n");
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci			/* AQ command to start FW DCBX agent will fail if
142962306a36Sopenharmony_ci			 * the agent is already started
143062306a36Sopenharmony_ci			 */
143162306a36Sopenharmony_ci			status = ice_aq_start_stop_dcbx(&pf->hw, true,
143262306a36Sopenharmony_ci							&dcbx_agent_status,
143362306a36Sopenharmony_ci							NULL);
143462306a36Sopenharmony_ci			if (status)
143562306a36Sopenharmony_ci				dev_dbg(dev, "Failed to start FW DCBX\n");
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci			dev_info(dev, "FW DCBX agent is %s\n",
143862306a36Sopenharmony_ci				 dcbx_agent_status ? "ACTIVE" : "DISABLED");
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci			/* Failure to configure MIB change or init DCB is not
144162306a36Sopenharmony_ci			 * relevant to ethtool.  Print notification that
144262306a36Sopenharmony_ci			 * registration/init failed but do not return error
144362306a36Sopenharmony_ci			 * state to ethtool
144462306a36Sopenharmony_ci			 */
144562306a36Sopenharmony_ci			status = ice_init_pf_dcb(pf, true);
144662306a36Sopenharmony_ci			if (status)
144762306a36Sopenharmony_ci				dev_dbg(dev, "Fail to init DCB\n");
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci			/* Register for MIB change events */
145062306a36Sopenharmony_ci			status = ice_cfg_lldp_mib_change(&pf->hw, true);
145162306a36Sopenharmony_ci			if (status)
145262306a36Sopenharmony_ci				dev_dbg(dev, "Fail to enable MIB change events\n");
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci			pf->dcbx_cap &= ~DCB_CAP_DCBX_HOST;
145562306a36Sopenharmony_ci			pf->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci			ice_nway_reset(netdev);
145862306a36Sopenharmony_ci		}
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) {
146162306a36Sopenharmony_ci		/* down and up VSI so that changes of Rx cfg are reflected. */
146262306a36Sopenharmony_ci		ice_down_up(vsi);
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci	/* don't allow modification of this flag when a single VF is in
146562306a36Sopenharmony_ci	 * promiscuous mode because it's not supported
146662306a36Sopenharmony_ci	 */
146762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, change_flags) &&
146862306a36Sopenharmony_ci	    ice_is_any_vf_in_unicast_promisc(pf)) {
146962306a36Sopenharmony_ci		dev_err(dev, "Changing vf-true-promisc-support flag while VF(s) are in promiscuous mode not supported\n");
147062306a36Sopenharmony_ci		/* toggle bit back to previous state */
147162306a36Sopenharmony_ci		change_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags);
147262306a36Sopenharmony_ci		ret = -EAGAIN;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_VF_VLAN_PRUNING, change_flags) &&
147662306a36Sopenharmony_ci	    ice_has_vfs(pf)) {
147762306a36Sopenharmony_ci		dev_err(dev, "vf-vlan-pruning: VLAN pruning cannot be changed while VFs are active.\n");
147862306a36Sopenharmony_ci		/* toggle bit back to previous state */
147962306a36Sopenharmony_ci		change_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags);
148062306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ciethtool_exit:
148362306a36Sopenharmony_ci	clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags);
148462306a36Sopenharmony_ci	return ret;
148562306a36Sopenharmony_ci}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_cistatic int ice_get_sset_count(struct net_device *netdev, int sset)
148862306a36Sopenharmony_ci{
148962306a36Sopenharmony_ci	switch (sset) {
149062306a36Sopenharmony_ci	case ETH_SS_STATS:
149162306a36Sopenharmony_ci		/* The number (and order) of strings reported *must* remain
149262306a36Sopenharmony_ci		 * constant for a given netdevice. This function must not
149362306a36Sopenharmony_ci		 * report a different number based on run time parameters
149462306a36Sopenharmony_ci		 * (such as the number of queues in use, or the setting of
149562306a36Sopenharmony_ci		 * a private ethtool flag). This is due to the nature of the
149662306a36Sopenharmony_ci		 * ethtool stats API.
149762306a36Sopenharmony_ci		 *
149862306a36Sopenharmony_ci		 * Userspace programs such as ethtool must make 3 separate
149962306a36Sopenharmony_ci		 * ioctl requests, one for size, one for the strings, and
150062306a36Sopenharmony_ci		 * finally one for the stats. Since these cross into
150162306a36Sopenharmony_ci		 * userspace, changes to the number or size could result in
150262306a36Sopenharmony_ci		 * undefined memory access or incorrect string<->value
150362306a36Sopenharmony_ci		 * correlations for statistics.
150462306a36Sopenharmony_ci		 *
150562306a36Sopenharmony_ci		 * Even if it appears to be safe, changes to the size or
150662306a36Sopenharmony_ci		 * order of strings will suffer from race conditions and are
150762306a36Sopenharmony_ci		 * not safe.
150862306a36Sopenharmony_ci		 */
150962306a36Sopenharmony_ci		return ICE_ALL_STATS_LEN(netdev);
151062306a36Sopenharmony_ci	case ETH_SS_TEST:
151162306a36Sopenharmony_ci		return ICE_TEST_LEN;
151262306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
151362306a36Sopenharmony_ci		return ICE_PRIV_FLAG_ARRAY_SIZE;
151462306a36Sopenharmony_ci	default:
151562306a36Sopenharmony_ci		return -EOPNOTSUPP;
151662306a36Sopenharmony_ci	}
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_cistatic void
152062306a36Sopenharmony_ci__ice_get_ethtool_stats(struct net_device *netdev,
152162306a36Sopenharmony_ci			struct ethtool_stats __always_unused *stats, u64 *data,
152262306a36Sopenharmony_ci			struct ice_vsi *vsi)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
152562306a36Sopenharmony_ci	struct ice_tx_ring *tx_ring;
152662306a36Sopenharmony_ci	struct ice_rx_ring *rx_ring;
152762306a36Sopenharmony_ci	unsigned int j;
152862306a36Sopenharmony_ci	int i = 0;
152962306a36Sopenharmony_ci	char *p;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	ice_update_pf_stats(pf);
153262306a36Sopenharmony_ci	ice_update_vsi_stats(vsi);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	for (j = 0; j < ICE_VSI_STATS_LEN; j++) {
153562306a36Sopenharmony_ci		p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset;
153662306a36Sopenharmony_ci		data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat ==
153762306a36Sopenharmony_ci			     sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	if (ice_is_port_repr_netdev(netdev))
154162306a36Sopenharmony_ci		return;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	/* populate per queue stats */
154462306a36Sopenharmony_ci	rcu_read_lock();
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	ice_for_each_alloc_txq(vsi, j) {
154762306a36Sopenharmony_ci		tx_ring = READ_ONCE(vsi->tx_rings[j]);
154862306a36Sopenharmony_ci		if (tx_ring && tx_ring->ring_stats) {
154962306a36Sopenharmony_ci			data[i++] = tx_ring->ring_stats->stats.pkts;
155062306a36Sopenharmony_ci			data[i++] = tx_ring->ring_stats->stats.bytes;
155162306a36Sopenharmony_ci		} else {
155262306a36Sopenharmony_ci			data[i++] = 0;
155362306a36Sopenharmony_ci			data[i++] = 0;
155462306a36Sopenharmony_ci		}
155562306a36Sopenharmony_ci	}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	ice_for_each_alloc_rxq(vsi, j) {
155862306a36Sopenharmony_ci		rx_ring = READ_ONCE(vsi->rx_rings[j]);
155962306a36Sopenharmony_ci		if (rx_ring && rx_ring->ring_stats) {
156062306a36Sopenharmony_ci			data[i++] = rx_ring->ring_stats->stats.pkts;
156162306a36Sopenharmony_ci			data[i++] = rx_ring->ring_stats->stats.bytes;
156262306a36Sopenharmony_ci		} else {
156362306a36Sopenharmony_ci			data[i++] = 0;
156462306a36Sopenharmony_ci			data[i++] = 0;
156562306a36Sopenharmony_ci		}
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	rcu_read_unlock();
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
157162306a36Sopenharmony_ci		return;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	for (j = 0; j < ICE_PF_STATS_LEN; j++) {
157462306a36Sopenharmony_ci		p = (char *)pf + ice_gstrings_pf_stats[j].stat_offset;
157562306a36Sopenharmony_ci		data[i++] = (ice_gstrings_pf_stats[j].sizeof_stat ==
157662306a36Sopenharmony_ci			     sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) {
158062306a36Sopenharmony_ci		data[i++] = pf->stats.priority_xon_tx[j];
158162306a36Sopenharmony_ci		data[i++] = pf->stats.priority_xoff_tx[j];
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	for (j = 0; j < ICE_MAX_USER_PRIORITY; j++) {
158562306a36Sopenharmony_ci		data[i++] = pf->stats.priority_xon_rx[j];
158662306a36Sopenharmony_ci		data[i++] = pf->stats.priority_xoff_rx[j];
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_cistatic void
159162306a36Sopenharmony_ciice_get_ethtool_stats(struct net_device *netdev,
159262306a36Sopenharmony_ci		      struct ethtool_stats __always_unused *stats, u64 *data)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	__ice_get_ethtool_stats(netdev, stats, data, np->vsi);
159762306a36Sopenharmony_ci}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci#define ICE_PHY_TYPE_LOW_MASK_MIN_1G	(ICE_PHY_TYPE_LOW_100BASE_TX | \
160062306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100M_SGMII)
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci#define ICE_PHY_TYPE_LOW_MASK_MIN_25G	(ICE_PHY_TYPE_LOW_MASK_MIN_1G | \
160362306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_1000BASE_T | \
160462306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_1000BASE_SX | \
160562306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_1000BASE_LX | \
160662306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_1000BASE_KX | \
160762306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_1G_SGMII | \
160862306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_2500BASE_T | \
160962306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_2500BASE_X | \
161062306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_2500BASE_KX | \
161162306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_5GBASE_T | \
161262306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_5GBASE_KR | \
161362306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10GBASE_T | \
161462306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10G_SFI_DA | \
161562306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10GBASE_SR | \
161662306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10GBASE_LR | \
161762306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10GBASE_KR_CR1 | \
161862306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC | \
161962306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_10G_SFI_C2C)
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci#define ICE_PHY_TYPE_LOW_MASK_100G	(ICE_PHY_TYPE_LOW_100GBASE_CR4 | \
162262306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_SR4 | \
162362306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_LR4 | \
162462306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_KR4 | \
162562306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC | \
162662306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100G_CAUI4 | \
162762306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC | \
162862306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100G_AUI4 | \
162962306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4 | \
163062306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4 | \
163162306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_CP2 | \
163262306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_SR2 | \
163362306a36Sopenharmony_ci					 ICE_PHY_TYPE_LOW_100GBASE_DR)
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci#define ICE_PHY_TYPE_HIGH_MASK_100G	(ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 | \
163662306a36Sopenharmony_ci					 ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC |\
163762306a36Sopenharmony_ci					 ICE_PHY_TYPE_HIGH_100G_CAUI2 | \
163862306a36Sopenharmony_ci					 ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | \
163962306a36Sopenharmony_ci					 ICE_PHY_TYPE_HIGH_100G_AUI2)
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci/**
164262306a36Sopenharmony_ci * ice_mask_min_supported_speeds
164362306a36Sopenharmony_ci * @hw: pointer to the HW structure
164462306a36Sopenharmony_ci * @phy_types_high: PHY type high
164562306a36Sopenharmony_ci * @phy_types_low: PHY type low to apply minimum supported speeds mask
164662306a36Sopenharmony_ci *
164762306a36Sopenharmony_ci * Apply minimum supported speeds mask to PHY type low. These are the speeds
164862306a36Sopenharmony_ci * for ethtool supported link mode.
164962306a36Sopenharmony_ci */
165062306a36Sopenharmony_cistatic void
165162306a36Sopenharmony_ciice_mask_min_supported_speeds(struct ice_hw *hw,
165262306a36Sopenharmony_ci			      u64 phy_types_high, u64 *phy_types_low)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	/* if QSFP connection with 100G speed, minimum supported speed is 25G */
165562306a36Sopenharmony_ci	if (*phy_types_low & ICE_PHY_TYPE_LOW_MASK_100G ||
165662306a36Sopenharmony_ci	    phy_types_high & ICE_PHY_TYPE_HIGH_MASK_100G)
165762306a36Sopenharmony_ci		*phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_25G;
165862306a36Sopenharmony_ci	else if (!ice_is_100m_speed_supported(hw))
165962306a36Sopenharmony_ci		*phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_1G;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci/**
166362306a36Sopenharmony_ci * ice_linkmode_set_bit - set link mode bit
166462306a36Sopenharmony_ci * @phy_to_ethtool: PHY type to ethtool link mode struct to set
166562306a36Sopenharmony_ci * @ks: ethtool link ksettings struct to fill out
166662306a36Sopenharmony_ci * @req_speeds: speed requested by user
166762306a36Sopenharmony_ci * @advert_phy_type: advertised PHY type
166862306a36Sopenharmony_ci * @phy_type: PHY type
166962306a36Sopenharmony_ci */
167062306a36Sopenharmony_cistatic void
167162306a36Sopenharmony_ciice_linkmode_set_bit(const struct ice_phy_type_to_ethtool *phy_to_ethtool,
167262306a36Sopenharmony_ci		     struct ethtool_link_ksettings *ks, u32 req_speeds,
167362306a36Sopenharmony_ci		     u64 advert_phy_type, u32 phy_type)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	linkmode_set_bit(phy_to_ethtool->link_mode, ks->link_modes.supported);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (req_speeds & phy_to_ethtool->aq_link_speed ||
167862306a36Sopenharmony_ci	    (!req_speeds && advert_phy_type & BIT(phy_type)))
167962306a36Sopenharmony_ci		linkmode_set_bit(phy_to_ethtool->link_mode,
168062306a36Sopenharmony_ci				 ks->link_modes.advertising);
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci/**
168462306a36Sopenharmony_ci * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes
168562306a36Sopenharmony_ci * @netdev: network interface device structure
168662306a36Sopenharmony_ci * @ks: ethtool link ksettings struct to fill out
168762306a36Sopenharmony_ci */
168862306a36Sopenharmony_cistatic void
168962306a36Sopenharmony_ciice_phy_type_to_ethtool(struct net_device *netdev,
169062306a36Sopenharmony_ci			struct ethtool_link_ksettings *ks)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
169362306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
169462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
169562306a36Sopenharmony_ci	u64 advert_phy_type_lo = 0;
169662306a36Sopenharmony_ci	u64 advert_phy_type_hi = 0;
169762306a36Sopenharmony_ci	u64 phy_types_high = 0;
169862306a36Sopenharmony_ci	u64 phy_types_low = 0;
169962306a36Sopenharmony_ci	u32 req_speeds;
170062306a36Sopenharmony_ci	u32 i;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	req_speeds = vsi->port_info->phy.link_info.req_speeds;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	/* Check if lenient mode is supported and enabled, or in strict mode.
170562306a36Sopenharmony_ci	 *
170662306a36Sopenharmony_ci	 * In lenient mode the Supported link modes are the PHY types without
170762306a36Sopenharmony_ci	 * media. The Advertising link mode is either 1. the user requested
170862306a36Sopenharmony_ci	 * speed, 2. the override PHY mask, or 3. the PHY types with media.
170962306a36Sopenharmony_ci	 *
171062306a36Sopenharmony_ci	 * In strict mode Supported link mode are the PHY type with media,
171162306a36Sopenharmony_ci	 * and Advertising link modes are the media PHY type or the speed
171262306a36Sopenharmony_ci	 * requested by user.
171362306a36Sopenharmony_ci	 */
171462306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) {
171562306a36Sopenharmony_ci		phy_types_low = le64_to_cpu(pf->nvm_phy_type_lo);
171662306a36Sopenharmony_ci		phy_types_high = le64_to_cpu(pf->nvm_phy_type_hi);
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci		ice_mask_min_supported_speeds(&pf->hw, phy_types_high,
171962306a36Sopenharmony_ci					      &phy_types_low);
172062306a36Sopenharmony_ci		/* determine advertised modes based on link override only
172162306a36Sopenharmony_ci		 * if it's supported and if the FW doesn't abstract the
172262306a36Sopenharmony_ci		 * driver from having to account for link overrides
172362306a36Sopenharmony_ci		 */
172462306a36Sopenharmony_ci		if (ice_fw_supports_link_override(&pf->hw) &&
172562306a36Sopenharmony_ci		    !ice_fw_supports_report_dflt_cfg(&pf->hw)) {
172662306a36Sopenharmony_ci			struct ice_link_default_override_tlv *ldo;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci			ldo = &pf->link_dflt_override;
172962306a36Sopenharmony_ci			/* If override enabled and PHY mask set, then
173062306a36Sopenharmony_ci			 * Advertising link mode is the intersection of the PHY
173162306a36Sopenharmony_ci			 * types without media and the override PHY mask.
173262306a36Sopenharmony_ci			 */
173362306a36Sopenharmony_ci			if (ldo->options & ICE_LINK_OVERRIDE_EN &&
173462306a36Sopenharmony_ci			    (ldo->phy_type_low || ldo->phy_type_high)) {
173562306a36Sopenharmony_ci				advert_phy_type_lo =
173662306a36Sopenharmony_ci					le64_to_cpu(pf->nvm_phy_type_lo) &
173762306a36Sopenharmony_ci					ldo->phy_type_low;
173862306a36Sopenharmony_ci				advert_phy_type_hi =
173962306a36Sopenharmony_ci					le64_to_cpu(pf->nvm_phy_type_hi) &
174062306a36Sopenharmony_ci					ldo->phy_type_high;
174162306a36Sopenharmony_ci			}
174262306a36Sopenharmony_ci		}
174362306a36Sopenharmony_ci	} else {
174462306a36Sopenharmony_ci		/* strict mode */
174562306a36Sopenharmony_ci		phy_types_low = vsi->port_info->phy.phy_type_low;
174662306a36Sopenharmony_ci		phy_types_high = vsi->port_info->phy.phy_type_high;
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	/* If Advertising link mode PHY type is not using override PHY type,
175062306a36Sopenharmony_ci	 * then use PHY type with media.
175162306a36Sopenharmony_ci	 */
175262306a36Sopenharmony_ci	if (!advert_phy_type_lo && !advert_phy_type_hi) {
175362306a36Sopenharmony_ci		advert_phy_type_lo = vsi->port_info->phy.phy_type_low;
175462306a36Sopenharmony_ci		advert_phy_type_hi = vsi->port_info->phy.phy_type_high;
175562306a36Sopenharmony_ci	}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	linkmode_zero(ks->link_modes.supported);
175862306a36Sopenharmony_ci	linkmode_zero(ks->link_modes.advertising);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(phy_type_low_lkup); i++) {
176162306a36Sopenharmony_ci		if (phy_types_low & BIT_ULL(i))
176262306a36Sopenharmony_ci			ice_linkmode_set_bit(&phy_type_low_lkup[i], ks,
176362306a36Sopenharmony_ci					     req_speeds, advert_phy_type_lo,
176462306a36Sopenharmony_ci					     i);
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(phy_type_high_lkup); i++) {
176862306a36Sopenharmony_ci		if (phy_types_high & BIT_ULL(i))
176962306a36Sopenharmony_ci			ice_linkmode_set_bit(&phy_type_high_lkup[i], ks,
177062306a36Sopenharmony_ci					     req_speeds, advert_phy_type_hi,
177162306a36Sopenharmony_ci					     i);
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci#define TEST_SET_BITS_TIMEOUT	50
177662306a36Sopenharmony_ci#define TEST_SET_BITS_SLEEP_MAX	2000
177762306a36Sopenharmony_ci#define TEST_SET_BITS_SLEEP_MIN	1000
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci/**
178062306a36Sopenharmony_ci * ice_get_settings_link_up - Get Link settings for when link is up
178162306a36Sopenharmony_ci * @ks: ethtool ksettings to fill in
178262306a36Sopenharmony_ci * @netdev: network interface device structure
178362306a36Sopenharmony_ci */
178462306a36Sopenharmony_cistatic void
178562306a36Sopenharmony_ciice_get_settings_link_up(struct ethtool_link_ksettings *ks,
178662306a36Sopenharmony_ci			 struct net_device *netdev)
178762306a36Sopenharmony_ci{
178862306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
178962306a36Sopenharmony_ci	struct ice_port_info *pi = np->vsi->port_info;
179062306a36Sopenharmony_ci	struct ice_link_status *link_info;
179162306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	link_info = &vsi->port_info->phy.link_info;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/* Get supported and advertised settings from PHY ability with media */
179662306a36Sopenharmony_ci	ice_phy_type_to_ethtool(netdev, ks);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	switch (link_info->link_speed) {
179962306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_100GB:
180062306a36Sopenharmony_ci		ks->base.speed = SPEED_100000;
180162306a36Sopenharmony_ci		break;
180262306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_50GB:
180362306a36Sopenharmony_ci		ks->base.speed = SPEED_50000;
180462306a36Sopenharmony_ci		break;
180562306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_40GB:
180662306a36Sopenharmony_ci		ks->base.speed = SPEED_40000;
180762306a36Sopenharmony_ci		break;
180862306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_25GB:
180962306a36Sopenharmony_ci		ks->base.speed = SPEED_25000;
181062306a36Sopenharmony_ci		break;
181162306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_20GB:
181262306a36Sopenharmony_ci		ks->base.speed = SPEED_20000;
181362306a36Sopenharmony_ci		break;
181462306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_10GB:
181562306a36Sopenharmony_ci		ks->base.speed = SPEED_10000;
181662306a36Sopenharmony_ci		break;
181762306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_5GB:
181862306a36Sopenharmony_ci		ks->base.speed = SPEED_5000;
181962306a36Sopenharmony_ci		break;
182062306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_2500MB:
182162306a36Sopenharmony_ci		ks->base.speed = SPEED_2500;
182262306a36Sopenharmony_ci		break;
182362306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_1000MB:
182462306a36Sopenharmony_ci		ks->base.speed = SPEED_1000;
182562306a36Sopenharmony_ci		break;
182662306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_100MB:
182762306a36Sopenharmony_ci		ks->base.speed = SPEED_100;
182862306a36Sopenharmony_ci		break;
182962306a36Sopenharmony_ci	default:
183062306a36Sopenharmony_ci		netdev_info(netdev, "WARNING: Unrecognized link_speed (0x%x).\n",
183162306a36Sopenharmony_ci			    link_info->link_speed);
183262306a36Sopenharmony_ci		break;
183362306a36Sopenharmony_ci	}
183462306a36Sopenharmony_ci	ks->base.duplex = DUPLEX_FULL;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	if (link_info->an_info & ICE_AQ_AN_COMPLETED)
183762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
183862306a36Sopenharmony_ci						     Autoneg);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	/* Set flow control negotiated Rx/Tx pause */
184162306a36Sopenharmony_ci	switch (pi->fc.current_mode) {
184262306a36Sopenharmony_ci	case ICE_FC_FULL:
184362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause);
184462306a36Sopenharmony_ci		break;
184562306a36Sopenharmony_ci	case ICE_FC_TX_PAUSE:
184662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause);
184762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
184862306a36Sopenharmony_ci						     Asym_Pause);
184962306a36Sopenharmony_ci		break;
185062306a36Sopenharmony_ci	case ICE_FC_RX_PAUSE:
185162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
185262306a36Sopenharmony_ci						     Asym_Pause);
185362306a36Sopenharmony_ci		break;
185462306a36Sopenharmony_ci	case ICE_FC_PFC:
185562306a36Sopenharmony_ci	default:
185662306a36Sopenharmony_ci		ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause);
185762306a36Sopenharmony_ci		ethtool_link_ksettings_del_link_mode(ks, lp_advertising,
185862306a36Sopenharmony_ci						     Asym_Pause);
185962306a36Sopenharmony_ci		break;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci/**
186462306a36Sopenharmony_ci * ice_get_settings_link_down - Get the Link settings when link is down
186562306a36Sopenharmony_ci * @ks: ethtool ksettings to fill in
186662306a36Sopenharmony_ci * @netdev: network interface device structure
186762306a36Sopenharmony_ci *
186862306a36Sopenharmony_ci * Reports link settings that can be determined when link is down
186962306a36Sopenharmony_ci */
187062306a36Sopenharmony_cistatic void
187162306a36Sopenharmony_ciice_get_settings_link_down(struct ethtool_link_ksettings *ks,
187262306a36Sopenharmony_ci			   struct net_device *netdev)
187362306a36Sopenharmony_ci{
187462306a36Sopenharmony_ci	/* link is down and the driver needs to fall back on
187562306a36Sopenharmony_ci	 * supported PHY types to figure out what info to display
187662306a36Sopenharmony_ci	 */
187762306a36Sopenharmony_ci	ice_phy_type_to_ethtool(netdev, ks);
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	/* With no link, speed and duplex are unknown */
188062306a36Sopenharmony_ci	ks->base.speed = SPEED_UNKNOWN;
188162306a36Sopenharmony_ci	ks->base.duplex = DUPLEX_UNKNOWN;
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci/**
188562306a36Sopenharmony_ci * ice_get_link_ksettings - Get Link Speed and Duplex settings
188662306a36Sopenharmony_ci * @netdev: network interface device structure
188762306a36Sopenharmony_ci * @ks: ethtool ksettings
188862306a36Sopenharmony_ci *
188962306a36Sopenharmony_ci * Reports speed/duplex settings based on media_type
189062306a36Sopenharmony_ci */
189162306a36Sopenharmony_cistatic int
189262306a36Sopenharmony_ciice_get_link_ksettings(struct net_device *netdev,
189362306a36Sopenharmony_ci		       struct ethtool_link_ksettings *ks)
189462306a36Sopenharmony_ci{
189562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
189662306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *caps;
189762306a36Sopenharmony_ci	struct ice_link_status *hw_link_info;
189862306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
189962306a36Sopenharmony_ci	int err;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(ks, supported);
190262306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(ks, advertising);
190362306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(ks, lp_advertising);
190462306a36Sopenharmony_ci	hw_link_info = &vsi->port_info->phy.link_info;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	/* set speed and duplex */
190762306a36Sopenharmony_ci	if (hw_link_info->link_info & ICE_AQ_LINK_UP)
190862306a36Sopenharmony_ci		ice_get_settings_link_up(ks, netdev);
190962306a36Sopenharmony_ci	else
191062306a36Sopenharmony_ci		ice_get_settings_link_down(ks, netdev);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	/* set autoneg settings */
191362306a36Sopenharmony_ci	ks->base.autoneg = (hw_link_info->an_info & ICE_AQ_AN_COMPLETED) ?
191462306a36Sopenharmony_ci		AUTONEG_ENABLE : AUTONEG_DISABLE;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	/* set media type settings */
191762306a36Sopenharmony_ci	switch (vsi->port_info->phy.media_type) {
191862306a36Sopenharmony_ci	case ICE_MEDIA_FIBER:
191962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE);
192062306a36Sopenharmony_ci		ks->base.port = PORT_FIBRE;
192162306a36Sopenharmony_ci		break;
192262306a36Sopenharmony_ci	case ICE_MEDIA_BASET:
192362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, TP);
192462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising, TP);
192562306a36Sopenharmony_ci		ks->base.port = PORT_TP;
192662306a36Sopenharmony_ci		break;
192762306a36Sopenharmony_ci	case ICE_MEDIA_BACKPLANE:
192862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, Backplane);
192962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising,
193062306a36Sopenharmony_ci						     Backplane);
193162306a36Sopenharmony_ci		ks->base.port = PORT_NONE;
193262306a36Sopenharmony_ci		break;
193362306a36Sopenharmony_ci	case ICE_MEDIA_DA:
193462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE);
193562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising, FIBRE);
193662306a36Sopenharmony_ci		ks->base.port = PORT_DA;
193762306a36Sopenharmony_ci		break;
193862306a36Sopenharmony_ci	default:
193962306a36Sopenharmony_ci		ks->base.port = PORT_OTHER;
194062306a36Sopenharmony_ci		break;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	/* flow control is symmetric and always supported */
194462306a36Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(ks, supported, Pause);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	caps = kzalloc(sizeof(*caps), GFP_KERNEL);
194762306a36Sopenharmony_ci	if (!caps)
194862306a36Sopenharmony_ci		return -ENOMEM;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	err = ice_aq_get_phy_caps(vsi->port_info, false,
195162306a36Sopenharmony_ci				  ICE_AQC_REPORT_ACTIVE_CFG, caps, NULL);
195262306a36Sopenharmony_ci	if (err)
195362306a36Sopenharmony_ci		goto done;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/* Set the advertised flow control based on the PHY capability */
195662306a36Sopenharmony_ci	if ((caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) &&
195762306a36Sopenharmony_ci	    (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)) {
195862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising, Pause);
195962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising,
196062306a36Sopenharmony_ci						     Asym_Pause);
196162306a36Sopenharmony_ci	} else if (caps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE) {
196262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising,
196362306a36Sopenharmony_ci						     Asym_Pause);
196462306a36Sopenharmony_ci	} else if (caps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE) {
196562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising, Pause);
196662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising,
196762306a36Sopenharmony_ci						     Asym_Pause);
196862306a36Sopenharmony_ci	} else {
196962306a36Sopenharmony_ci		ethtool_link_ksettings_del_link_mode(ks, advertising, Pause);
197062306a36Sopenharmony_ci		ethtool_link_ksettings_del_link_mode(ks, advertising,
197162306a36Sopenharmony_ci						     Asym_Pause);
197262306a36Sopenharmony_ci	}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	/* Set advertised FEC modes based on PHY capability */
197562306a36Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
197862306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
197962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising,
198062306a36Sopenharmony_ci						     FEC_BASER);
198162306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
198262306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
198362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	err = ice_aq_get_phy_caps(vsi->port_info, false,
198662306a36Sopenharmony_ci				  ICE_AQC_REPORT_TOPO_CAP_MEDIA, caps, NULL);
198762306a36Sopenharmony_ci	if (err)
198862306a36Sopenharmony_ci		goto done;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	/* Set supported FEC modes based on PHY capability */
199162306a36Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
199462306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN)
199562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
199662306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
199762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	/* Set supported and advertised autoneg */
200062306a36Sopenharmony_ci	if (ice_is_phy_caps_an_enabled(caps)) {
200162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg);
200262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(ks, advertising, Autoneg);
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cidone:
200662306a36Sopenharmony_ci	kfree(caps);
200762306a36Sopenharmony_ci	return err;
200862306a36Sopenharmony_ci}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci/**
201162306a36Sopenharmony_ci * ice_ksettings_find_adv_link_speed - Find advertising link speed
201262306a36Sopenharmony_ci * @ks: ethtool ksettings
201362306a36Sopenharmony_ci */
201462306a36Sopenharmony_cistatic u16
201562306a36Sopenharmony_ciice_ksettings_find_adv_link_speed(const struct ethtool_link_ksettings *ks)
201662306a36Sopenharmony_ci{
201762306a36Sopenharmony_ci	u16 adv_link_speed = 0;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
202062306a36Sopenharmony_ci						  100baseT_Full))
202162306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_100MB;
202262306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
202362306a36Sopenharmony_ci						  1000baseX_Full) ||
202462306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
202562306a36Sopenharmony_ci						  1000baseT_Full) ||
202662306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
202762306a36Sopenharmony_ci						  1000baseKX_Full))
202862306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_1000MB;
202962306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
203062306a36Sopenharmony_ci						  2500baseT_Full) ||
203162306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
203262306a36Sopenharmony_ci						  2500baseX_Full))
203362306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_2500MB;
203462306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
203562306a36Sopenharmony_ci						  5000baseT_Full))
203662306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_5GB;
203762306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
203862306a36Sopenharmony_ci						  10000baseT_Full) ||
203962306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
204062306a36Sopenharmony_ci						  10000baseKR_Full) ||
204162306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
204262306a36Sopenharmony_ci						  10000baseSR_Full) ||
204362306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
204462306a36Sopenharmony_ci						  10000baseLR_Full))
204562306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_10GB;
204662306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
204762306a36Sopenharmony_ci						  25000baseCR_Full) ||
204862306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
204962306a36Sopenharmony_ci						  25000baseSR_Full) ||
205062306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
205162306a36Sopenharmony_ci						  25000baseKR_Full))
205262306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_25GB;
205362306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
205462306a36Sopenharmony_ci						  40000baseCR4_Full) ||
205562306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
205662306a36Sopenharmony_ci						  40000baseSR4_Full) ||
205762306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
205862306a36Sopenharmony_ci						  40000baseLR4_Full) ||
205962306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
206062306a36Sopenharmony_ci						  40000baseKR4_Full))
206162306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_40GB;
206262306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
206362306a36Sopenharmony_ci						  50000baseCR2_Full) ||
206462306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
206562306a36Sopenharmony_ci						  50000baseKR2_Full) ||
206662306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
206762306a36Sopenharmony_ci						  50000baseSR2_Full))
206862306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_50GB;
206962306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
207062306a36Sopenharmony_ci						  100000baseCR4_Full) ||
207162306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
207262306a36Sopenharmony_ci						  100000baseSR4_Full) ||
207362306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
207462306a36Sopenharmony_ci						  100000baseLR4_ER4_Full) ||
207562306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
207662306a36Sopenharmony_ci						  100000baseKR4_Full) ||
207762306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
207862306a36Sopenharmony_ci						  100000baseCR2_Full) ||
207962306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
208062306a36Sopenharmony_ci						  100000baseSR2_Full) ||
208162306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(ks, advertising,
208262306a36Sopenharmony_ci						  100000baseKR2_Full))
208362306a36Sopenharmony_ci		adv_link_speed |= ICE_AQ_LINK_SPEED_100GB;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	return adv_link_speed;
208662306a36Sopenharmony_ci}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci/**
208962306a36Sopenharmony_ci * ice_setup_autoneg
209062306a36Sopenharmony_ci * @p: port info
209162306a36Sopenharmony_ci * @ks: ethtool_link_ksettings
209262306a36Sopenharmony_ci * @config: configuration that will be sent down to FW
209362306a36Sopenharmony_ci * @autoneg_enabled: autonegotiation is enabled or not
209462306a36Sopenharmony_ci * @autoneg_changed: will there a change in autonegotiation
209562306a36Sopenharmony_ci * @netdev: network interface device structure
209662306a36Sopenharmony_ci *
209762306a36Sopenharmony_ci * Setup PHY autonegotiation feature
209862306a36Sopenharmony_ci */
209962306a36Sopenharmony_cistatic int
210062306a36Sopenharmony_ciice_setup_autoneg(struct ice_port_info *p, struct ethtool_link_ksettings *ks,
210162306a36Sopenharmony_ci		  struct ice_aqc_set_phy_cfg_data *config,
210262306a36Sopenharmony_ci		  u8 autoneg_enabled, u8 *autoneg_changed,
210362306a36Sopenharmony_ci		  struct net_device *netdev)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	int err = 0;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	*autoneg_changed = 0;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	/* Check autoneg */
211062306a36Sopenharmony_ci	if (autoneg_enabled == AUTONEG_ENABLE) {
211162306a36Sopenharmony_ci		/* If autoneg was not already enabled */
211262306a36Sopenharmony_ci		if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) {
211362306a36Sopenharmony_ci			/* If autoneg is not supported, return error */
211462306a36Sopenharmony_ci			if (!ethtool_link_ksettings_test_link_mode(ks,
211562306a36Sopenharmony_ci								   supported,
211662306a36Sopenharmony_ci								   Autoneg)) {
211762306a36Sopenharmony_ci				netdev_info(netdev, "Autoneg not supported on this phy.\n");
211862306a36Sopenharmony_ci				err = -EINVAL;
211962306a36Sopenharmony_ci			} else {
212062306a36Sopenharmony_ci				/* Autoneg is allowed to change */
212162306a36Sopenharmony_ci				config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
212262306a36Sopenharmony_ci				*autoneg_changed = 1;
212362306a36Sopenharmony_ci			}
212462306a36Sopenharmony_ci		}
212562306a36Sopenharmony_ci	} else {
212662306a36Sopenharmony_ci		/* If autoneg is currently enabled */
212762306a36Sopenharmony_ci		if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) {
212862306a36Sopenharmony_ci			/* If autoneg is supported 10GBASE_T is the only PHY
212962306a36Sopenharmony_ci			 * that can disable it, so otherwise return error
213062306a36Sopenharmony_ci			 */
213162306a36Sopenharmony_ci			if (ethtool_link_ksettings_test_link_mode(ks,
213262306a36Sopenharmony_ci								  supported,
213362306a36Sopenharmony_ci								  Autoneg)) {
213462306a36Sopenharmony_ci				netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
213562306a36Sopenharmony_ci				err = -EINVAL;
213662306a36Sopenharmony_ci			} else {
213762306a36Sopenharmony_ci				/* Autoneg is allowed to change */
213862306a36Sopenharmony_ci				config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
213962306a36Sopenharmony_ci				*autoneg_changed = 1;
214062306a36Sopenharmony_ci			}
214162306a36Sopenharmony_ci		}
214262306a36Sopenharmony_ci	}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	return err;
214562306a36Sopenharmony_ci}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci/**
214862306a36Sopenharmony_ci * ice_set_phy_type_from_speed - set phy_types based on speeds
214962306a36Sopenharmony_ci * and advertised modes
215062306a36Sopenharmony_ci * @ks: ethtool link ksettings struct
215162306a36Sopenharmony_ci * @phy_type_low: pointer to the lower part of phy_type
215262306a36Sopenharmony_ci * @phy_type_high: pointer to the higher part of phy_type
215362306a36Sopenharmony_ci * @adv_link_speed: targeted link speeds bitmap
215462306a36Sopenharmony_ci */
215562306a36Sopenharmony_cistatic void
215662306a36Sopenharmony_ciice_set_phy_type_from_speed(const struct ethtool_link_ksettings *ks,
215762306a36Sopenharmony_ci			    u64 *phy_type_low, u64 *phy_type_high,
215862306a36Sopenharmony_ci			    u16 adv_link_speed)
215962306a36Sopenharmony_ci{
216062306a36Sopenharmony_ci	/* Handle 1000M speed in a special way because ice_update_phy_type
216162306a36Sopenharmony_ci	 * enables all link modes, but having mixed copper and optical
216262306a36Sopenharmony_ci	 * standards is not supported.
216362306a36Sopenharmony_ci	 */
216462306a36Sopenharmony_ci	adv_link_speed &= ~ICE_AQ_LINK_SPEED_1000MB;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
216762306a36Sopenharmony_ci						  1000baseT_Full))
216862306a36Sopenharmony_ci		*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_T |
216962306a36Sopenharmony_ci				 ICE_PHY_TYPE_LOW_1G_SGMII;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
217262306a36Sopenharmony_ci						  1000baseKX_Full))
217362306a36Sopenharmony_ci		*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_KX;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(ks, advertising,
217662306a36Sopenharmony_ci						  1000baseX_Full))
217762306a36Sopenharmony_ci		*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_SX |
217862306a36Sopenharmony_ci				 ICE_PHY_TYPE_LOW_1000BASE_LX;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	ice_update_phy_type(phy_type_low, phy_type_high, adv_link_speed);
218162306a36Sopenharmony_ci}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci/**
218462306a36Sopenharmony_ci * ice_set_link_ksettings - Set Speed and Duplex
218562306a36Sopenharmony_ci * @netdev: network interface device structure
218662306a36Sopenharmony_ci * @ks: ethtool ksettings
218762306a36Sopenharmony_ci *
218862306a36Sopenharmony_ci * Set speed/duplex per media_types advertised/forced
218962306a36Sopenharmony_ci */
219062306a36Sopenharmony_cistatic int
219162306a36Sopenharmony_ciice_set_link_ksettings(struct net_device *netdev,
219262306a36Sopenharmony_ci		       const struct ethtool_link_ksettings *ks)
219362306a36Sopenharmony_ci{
219462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
219562306a36Sopenharmony_ci	u8 autoneg, timeout = TEST_SET_BITS_TIMEOUT;
219662306a36Sopenharmony_ci	struct ethtool_link_ksettings copy_ks = *ks;
219762306a36Sopenharmony_ci	struct ethtool_link_ksettings safe_ks = {};
219862306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *phy_caps;
219962306a36Sopenharmony_ci	struct ice_aqc_set_phy_cfg_data config;
220062306a36Sopenharmony_ci	u16 adv_link_speed, curr_link_speed;
220162306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
220262306a36Sopenharmony_ci	struct ice_port_info *pi;
220362306a36Sopenharmony_ci	u8 autoneg_changed = 0;
220462306a36Sopenharmony_ci	u64 phy_type_high = 0;
220562306a36Sopenharmony_ci	u64 phy_type_low = 0;
220662306a36Sopenharmony_ci	bool linkup;
220762306a36Sopenharmony_ci	int err;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	pi = np->vsi->port_info;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	if (!pi)
221262306a36Sopenharmony_ci		return -EIO;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if (pi->phy.media_type != ICE_MEDIA_BASET &&
221562306a36Sopenharmony_ci	    pi->phy.media_type != ICE_MEDIA_FIBER &&
221662306a36Sopenharmony_ci	    pi->phy.media_type != ICE_MEDIA_BACKPLANE &&
221762306a36Sopenharmony_ci	    pi->phy.media_type != ICE_MEDIA_DA &&
221862306a36Sopenharmony_ci	    pi->phy.link_info.link_info & ICE_AQ_LINK_UP)
221962306a36Sopenharmony_ci		return -EOPNOTSUPP;
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	phy_caps = kzalloc(sizeof(*phy_caps), GFP_KERNEL);
222262306a36Sopenharmony_ci	if (!phy_caps)
222362306a36Sopenharmony_ci		return -ENOMEM;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	/* Get the PHY capabilities based on media */
222662306a36Sopenharmony_ci	if (ice_fw_supports_report_dflt_cfg(pi->hw))
222762306a36Sopenharmony_ci		err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_DFLT_CFG,
222862306a36Sopenharmony_ci					  phy_caps, NULL);
222962306a36Sopenharmony_ci	else
223062306a36Sopenharmony_ci		err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA,
223162306a36Sopenharmony_ci					  phy_caps, NULL);
223262306a36Sopenharmony_ci	if (err)
223362306a36Sopenharmony_ci		goto done;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	/* save autoneg out of ksettings */
223662306a36Sopenharmony_ci	autoneg = copy_ks.base.autoneg;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	/* Get link modes supported by hardware.*/
223962306a36Sopenharmony_ci	ice_phy_type_to_ethtool(netdev, &safe_ks);
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	/* and check against modes requested by user.
224262306a36Sopenharmony_ci	 * Return an error if unsupported mode was set.
224362306a36Sopenharmony_ci	 */
224462306a36Sopenharmony_ci	if (!bitmap_subset(copy_ks.link_modes.advertising,
224562306a36Sopenharmony_ci			   safe_ks.link_modes.supported,
224662306a36Sopenharmony_ci			   __ETHTOOL_LINK_MODE_MASK_NBITS)) {
224762306a36Sopenharmony_ci		if (!test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags))
224862306a36Sopenharmony_ci			netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
224962306a36Sopenharmony_ci		err = -EOPNOTSUPP;
225062306a36Sopenharmony_ci		goto done;
225162306a36Sopenharmony_ci	}
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	/* get our own copy of the bits to check against */
225462306a36Sopenharmony_ci	memset(&safe_ks, 0, sizeof(safe_ks));
225562306a36Sopenharmony_ci	safe_ks.base.cmd = copy_ks.base.cmd;
225662306a36Sopenharmony_ci	safe_ks.base.link_mode_masks_nwords =
225762306a36Sopenharmony_ci		copy_ks.base.link_mode_masks_nwords;
225862306a36Sopenharmony_ci	ice_get_link_ksettings(netdev, &safe_ks);
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	/* set autoneg back to what it currently is */
226162306a36Sopenharmony_ci	copy_ks.base.autoneg = safe_ks.base.autoneg;
226262306a36Sopenharmony_ci	/* we don't compare the speed */
226362306a36Sopenharmony_ci	copy_ks.base.speed = safe_ks.base.speed;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	/* If copy_ks.base and safe_ks.base are not the same now, then they are
226662306a36Sopenharmony_ci	 * trying to set something that we do not support.
226762306a36Sopenharmony_ci	 */
226862306a36Sopenharmony_ci	if (memcmp(&copy_ks.base, &safe_ks.base, sizeof(copy_ks.base))) {
226962306a36Sopenharmony_ci		err = -EOPNOTSUPP;
227062306a36Sopenharmony_ci		goto done;
227162306a36Sopenharmony_ci	}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	while (test_and_set_bit(ICE_CFG_BUSY, pf->state)) {
227462306a36Sopenharmony_ci		timeout--;
227562306a36Sopenharmony_ci		if (!timeout) {
227662306a36Sopenharmony_ci			err = -EBUSY;
227762306a36Sopenharmony_ci			goto done;
227862306a36Sopenharmony_ci		}
227962306a36Sopenharmony_ci		usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX);
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	/* Copy the current user PHY configuration. The current user PHY
228362306a36Sopenharmony_ci	 * configuration is initialized during probe from PHY capabilities
228462306a36Sopenharmony_ci	 * software mode, and updated on set PHY configuration.
228562306a36Sopenharmony_ci	 */
228662306a36Sopenharmony_ci	config = pi->phy.curr_user_phy_cfg;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	/* Check autoneg */
229162306a36Sopenharmony_ci	err = ice_setup_autoneg(pi, &safe_ks, &config, autoneg, &autoneg_changed,
229262306a36Sopenharmony_ci				netdev);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	if (err)
229562306a36Sopenharmony_ci		goto done;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	/* Call to get the current link speed */
229862306a36Sopenharmony_ci	pi->phy.get_link_info = true;
229962306a36Sopenharmony_ci	err = ice_get_link_status(pi, &linkup);
230062306a36Sopenharmony_ci	if (err)
230162306a36Sopenharmony_ci		goto done;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	curr_link_speed = pi->phy.curr_user_speed_req;
230462306a36Sopenharmony_ci	adv_link_speed = ice_ksettings_find_adv_link_speed(ks);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	/* If speed didn't get set, set it to what it currently is.
230762306a36Sopenharmony_ci	 * This is needed because if advertise is 0 (as it is when autoneg
230862306a36Sopenharmony_ci	 * is disabled) then speed won't get set.
230962306a36Sopenharmony_ci	 */
231062306a36Sopenharmony_ci	if (!adv_link_speed)
231162306a36Sopenharmony_ci		adv_link_speed = curr_link_speed;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	/* Convert the advertise link speeds to their corresponded PHY_TYPE */
231462306a36Sopenharmony_ci	ice_set_phy_type_from_speed(ks, &phy_type_low, &phy_type_high,
231562306a36Sopenharmony_ci				    adv_link_speed);
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	if (!autoneg_changed && adv_link_speed == curr_link_speed) {
231862306a36Sopenharmony_ci		netdev_info(netdev, "Nothing changed, exiting without setting anything.\n");
231962306a36Sopenharmony_ci		goto done;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	/* save the requested speeds */
232362306a36Sopenharmony_ci	pi->phy.link_info.req_speeds = adv_link_speed;
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	/* set link and auto negotiation so changes take effect */
232662306a36Sopenharmony_ci	config.caps |= ICE_AQ_PHY_ENA_LINK;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	/* check if there is a PHY type for the requested advertised speed */
232962306a36Sopenharmony_ci	if (!(phy_type_low || phy_type_high)) {
233062306a36Sopenharmony_ci		netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
233162306a36Sopenharmony_ci		err = -EOPNOTSUPP;
233262306a36Sopenharmony_ci		goto done;
233362306a36Sopenharmony_ci	}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	/* intersect requested advertised speed PHY types with media PHY types
233662306a36Sopenharmony_ci	 * for set PHY configuration
233762306a36Sopenharmony_ci	 */
233862306a36Sopenharmony_ci	config.phy_type_high = cpu_to_le64(phy_type_high) &
233962306a36Sopenharmony_ci			phy_caps->phy_type_high;
234062306a36Sopenharmony_ci	config.phy_type_low = cpu_to_le64(phy_type_low) &
234162306a36Sopenharmony_ci			phy_caps->phy_type_low;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	if (!(config.phy_type_high || config.phy_type_low)) {
234462306a36Sopenharmony_ci		/* If there is no intersection and lenient mode is enabled, then
234562306a36Sopenharmony_ci		 * intersect the requested advertised speed with NVM media type
234662306a36Sopenharmony_ci		 * PHY types.
234762306a36Sopenharmony_ci		 */
234862306a36Sopenharmony_ci		if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) {
234962306a36Sopenharmony_ci			config.phy_type_high = cpu_to_le64(phy_type_high) &
235062306a36Sopenharmony_ci					       pf->nvm_phy_type_hi;
235162306a36Sopenharmony_ci			config.phy_type_low = cpu_to_le64(phy_type_low) &
235262306a36Sopenharmony_ci					      pf->nvm_phy_type_lo;
235362306a36Sopenharmony_ci		} else {
235462306a36Sopenharmony_ci			netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
235562306a36Sopenharmony_ci			err = -EOPNOTSUPP;
235662306a36Sopenharmony_ci			goto done;
235762306a36Sopenharmony_ci		}
235862306a36Sopenharmony_ci	}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	/* If link is up put link down */
236162306a36Sopenharmony_ci	if (pi->phy.link_info.link_info & ICE_AQ_LINK_UP) {
236262306a36Sopenharmony_ci		/* Tell the OS link is going down, the link will go
236362306a36Sopenharmony_ci		 * back up when fw says it is ready asynchronously
236462306a36Sopenharmony_ci		 */
236562306a36Sopenharmony_ci		ice_print_link_msg(np->vsi, false);
236662306a36Sopenharmony_ci		netif_carrier_off(netdev);
236762306a36Sopenharmony_ci		netif_tx_stop_all_queues(netdev);
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	/* make the aq call */
237162306a36Sopenharmony_ci	err = ice_aq_set_phy_cfg(&pf->hw, pi, &config, NULL);
237262306a36Sopenharmony_ci	if (err) {
237362306a36Sopenharmony_ci		netdev_info(netdev, "Set phy config failed,\n");
237462306a36Sopenharmony_ci		goto done;
237562306a36Sopenharmony_ci	}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	/* Save speed request */
237862306a36Sopenharmony_ci	pi->phy.curr_user_speed_req = adv_link_speed;
237962306a36Sopenharmony_cidone:
238062306a36Sopenharmony_ci	kfree(phy_caps);
238162306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, pf->state);
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	return err;
238462306a36Sopenharmony_ci}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci/**
238762306a36Sopenharmony_ci * ice_parse_hdrs - parses headers from RSS hash input
238862306a36Sopenharmony_ci * @nfc: ethtool rxnfc command
238962306a36Sopenharmony_ci *
239062306a36Sopenharmony_ci * This function parses the rxnfc command and returns intended
239162306a36Sopenharmony_ci * header types for RSS configuration
239262306a36Sopenharmony_ci */
239362306a36Sopenharmony_cistatic u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc)
239462306a36Sopenharmony_ci{
239562306a36Sopenharmony_ci	u32 hdrs = ICE_FLOW_SEG_HDR_NONE;
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	switch (nfc->flow_type) {
239862306a36Sopenharmony_ci	case TCP_V4_FLOW:
239962306a36Sopenharmony_ci		hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4;
240062306a36Sopenharmony_ci		break;
240162306a36Sopenharmony_ci	case UDP_V4_FLOW:
240262306a36Sopenharmony_ci		hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4;
240362306a36Sopenharmony_ci		break;
240462306a36Sopenharmony_ci	case SCTP_V4_FLOW:
240562306a36Sopenharmony_ci		hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4;
240662306a36Sopenharmony_ci		break;
240762306a36Sopenharmony_ci	case TCP_V6_FLOW:
240862306a36Sopenharmony_ci		hdrs |= ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6;
240962306a36Sopenharmony_ci		break;
241062306a36Sopenharmony_ci	case UDP_V6_FLOW:
241162306a36Sopenharmony_ci		hdrs |= ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6;
241262306a36Sopenharmony_ci		break;
241362306a36Sopenharmony_ci	case SCTP_V6_FLOW:
241462306a36Sopenharmony_ci		hdrs |= ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6;
241562306a36Sopenharmony_ci		break;
241662306a36Sopenharmony_ci	default:
241762306a36Sopenharmony_ci		break;
241862306a36Sopenharmony_ci	}
241962306a36Sopenharmony_ci	return hdrs;
242062306a36Sopenharmony_ci}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV4_SA	BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)
242362306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV6_SA	BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)
242462306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV4_DA	BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)
242562306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_IPV6_DA	BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)
242662306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_TCP_SRC_PORT	BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)
242762306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_TCP_DST_PORT	BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)
242862306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_UDP_SRC_PORT	BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)
242962306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_UDP_DST_PORT	BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)
243062306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_SCTP_SRC_PORT	\
243162306a36Sopenharmony_ci	BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)
243262306a36Sopenharmony_ci#define ICE_FLOW_HASH_FLD_SCTP_DST_PORT	\
243362306a36Sopenharmony_ci	BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci/**
243662306a36Sopenharmony_ci * ice_parse_hash_flds - parses hash fields from RSS hash input
243762306a36Sopenharmony_ci * @nfc: ethtool rxnfc command
243862306a36Sopenharmony_ci *
243962306a36Sopenharmony_ci * This function parses the rxnfc command and returns intended
244062306a36Sopenharmony_ci * hash fields for RSS configuration
244162306a36Sopenharmony_ci */
244262306a36Sopenharmony_cistatic u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc)
244362306a36Sopenharmony_ci{
244462306a36Sopenharmony_ci	u64 hfld = ICE_HASH_INVALID;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	if (nfc->data & RXH_IP_SRC || nfc->data & RXH_IP_DST) {
244762306a36Sopenharmony_ci		switch (nfc->flow_type) {
244862306a36Sopenharmony_ci		case TCP_V4_FLOW:
244962306a36Sopenharmony_ci		case UDP_V4_FLOW:
245062306a36Sopenharmony_ci		case SCTP_V4_FLOW:
245162306a36Sopenharmony_ci			if (nfc->data & RXH_IP_SRC)
245262306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_IPV4_SA;
245362306a36Sopenharmony_ci			if (nfc->data & RXH_IP_DST)
245462306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_IPV4_DA;
245562306a36Sopenharmony_ci			break;
245662306a36Sopenharmony_ci		case TCP_V6_FLOW:
245762306a36Sopenharmony_ci		case UDP_V6_FLOW:
245862306a36Sopenharmony_ci		case SCTP_V6_FLOW:
245962306a36Sopenharmony_ci			if (nfc->data & RXH_IP_SRC)
246062306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_IPV6_SA;
246162306a36Sopenharmony_ci			if (nfc->data & RXH_IP_DST)
246262306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_IPV6_DA;
246362306a36Sopenharmony_ci			break;
246462306a36Sopenharmony_ci		default:
246562306a36Sopenharmony_ci			break;
246662306a36Sopenharmony_ci		}
246762306a36Sopenharmony_ci	}
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	if (nfc->data & RXH_L4_B_0_1 || nfc->data & RXH_L4_B_2_3) {
247062306a36Sopenharmony_ci		switch (nfc->flow_type) {
247162306a36Sopenharmony_ci		case TCP_V4_FLOW:
247262306a36Sopenharmony_ci		case TCP_V6_FLOW:
247362306a36Sopenharmony_ci			if (nfc->data & RXH_L4_B_0_1)
247462306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_TCP_SRC_PORT;
247562306a36Sopenharmony_ci			if (nfc->data & RXH_L4_B_2_3)
247662306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_TCP_DST_PORT;
247762306a36Sopenharmony_ci			break;
247862306a36Sopenharmony_ci		case UDP_V4_FLOW:
247962306a36Sopenharmony_ci		case UDP_V6_FLOW:
248062306a36Sopenharmony_ci			if (nfc->data & RXH_L4_B_0_1)
248162306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_UDP_SRC_PORT;
248262306a36Sopenharmony_ci			if (nfc->data & RXH_L4_B_2_3)
248362306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_UDP_DST_PORT;
248462306a36Sopenharmony_ci			break;
248562306a36Sopenharmony_ci		case SCTP_V4_FLOW:
248662306a36Sopenharmony_ci		case SCTP_V6_FLOW:
248762306a36Sopenharmony_ci			if (nfc->data & RXH_L4_B_0_1)
248862306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_SCTP_SRC_PORT;
248962306a36Sopenharmony_ci			if (nfc->data & RXH_L4_B_2_3)
249062306a36Sopenharmony_ci				hfld |= ICE_FLOW_HASH_FLD_SCTP_DST_PORT;
249162306a36Sopenharmony_ci			break;
249262306a36Sopenharmony_ci		default:
249362306a36Sopenharmony_ci			break;
249462306a36Sopenharmony_ci		}
249562306a36Sopenharmony_ci	}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	return hfld;
249862306a36Sopenharmony_ci}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci/**
250162306a36Sopenharmony_ci * ice_set_rss_hash_opt - Enable/Disable flow types for RSS hash
250262306a36Sopenharmony_ci * @vsi: the VSI being configured
250362306a36Sopenharmony_ci * @nfc: ethtool rxnfc command
250462306a36Sopenharmony_ci *
250562306a36Sopenharmony_ci * Returns Success if the flow input set is supported.
250662306a36Sopenharmony_ci */
250762306a36Sopenharmony_cistatic int
250862306a36Sopenharmony_ciice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
250962306a36Sopenharmony_ci{
251062306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
251162306a36Sopenharmony_ci	struct device *dev;
251262306a36Sopenharmony_ci	u64 hashed_flds;
251362306a36Sopenharmony_ci	int status;
251462306a36Sopenharmony_ci	u32 hdrs;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
251762306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
251862306a36Sopenharmony_ci		dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n",
251962306a36Sopenharmony_ci			vsi->vsi_num);
252062306a36Sopenharmony_ci		return -EINVAL;
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	hashed_flds = ice_parse_hash_flds(nfc);
252462306a36Sopenharmony_ci	if (hashed_flds == ICE_HASH_INVALID) {
252562306a36Sopenharmony_ci		dev_dbg(dev, "Invalid hash fields, vsi num = %d\n",
252662306a36Sopenharmony_ci			vsi->vsi_num);
252762306a36Sopenharmony_ci		return -EINVAL;
252862306a36Sopenharmony_ci	}
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	hdrs = ice_parse_hdrs(nfc);
253162306a36Sopenharmony_ci	if (hdrs == ICE_FLOW_SEG_HDR_NONE) {
253262306a36Sopenharmony_ci		dev_dbg(dev, "Header type is not valid, vsi num = %d\n",
253362306a36Sopenharmony_ci			vsi->vsi_num);
253462306a36Sopenharmony_ci		return -EINVAL;
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	status = ice_add_rss_cfg(&pf->hw, vsi->idx, hashed_flds, hdrs);
253862306a36Sopenharmony_ci	if (status) {
253962306a36Sopenharmony_ci		dev_dbg(dev, "ice_add_rss_cfg failed, vsi num = %d, error = %d\n",
254062306a36Sopenharmony_ci			vsi->vsi_num, status);
254162306a36Sopenharmony_ci		return status;
254262306a36Sopenharmony_ci	}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	return 0;
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci/**
254862306a36Sopenharmony_ci * ice_get_rss_hash_opt - Retrieve hash fields for a given flow-type
254962306a36Sopenharmony_ci * @vsi: the VSI being configured
255062306a36Sopenharmony_ci * @nfc: ethtool rxnfc command
255162306a36Sopenharmony_ci */
255262306a36Sopenharmony_cistatic void
255362306a36Sopenharmony_ciice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
255462306a36Sopenharmony_ci{
255562306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
255662306a36Sopenharmony_ci	struct device *dev;
255762306a36Sopenharmony_ci	u64 hash_flds;
255862306a36Sopenharmony_ci	u32 hdrs;
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	nfc->data = 0;
256362306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
256462306a36Sopenharmony_ci		dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n",
256562306a36Sopenharmony_ci			vsi->vsi_num);
256662306a36Sopenharmony_ci		return;
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	hdrs = ice_parse_hdrs(nfc);
257062306a36Sopenharmony_ci	if (hdrs == ICE_FLOW_SEG_HDR_NONE) {
257162306a36Sopenharmony_ci		dev_dbg(dev, "Header type is not valid, vsi num = %d\n",
257262306a36Sopenharmony_ci			vsi->vsi_num);
257362306a36Sopenharmony_ci		return;
257462306a36Sopenharmony_ci	}
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	hash_flds = ice_get_rss_cfg(&pf->hw, vsi->idx, hdrs);
257762306a36Sopenharmony_ci	if (hash_flds == ICE_HASH_INVALID) {
257862306a36Sopenharmony_ci		dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n",
257962306a36Sopenharmony_ci			vsi->vsi_num);
258062306a36Sopenharmony_ci		return;
258162306a36Sopenharmony_ci	}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_SA ||
258462306a36Sopenharmony_ci	    hash_flds & ICE_FLOW_HASH_FLD_IPV6_SA)
258562306a36Sopenharmony_ci		nfc->data |= (u64)RXH_IP_SRC;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	if (hash_flds & ICE_FLOW_HASH_FLD_IPV4_DA ||
258862306a36Sopenharmony_ci	    hash_flds & ICE_FLOW_HASH_FLD_IPV6_DA)
258962306a36Sopenharmony_ci		nfc->data |= (u64)RXH_IP_DST;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	if (hash_flds & ICE_FLOW_HASH_FLD_TCP_SRC_PORT ||
259262306a36Sopenharmony_ci	    hash_flds & ICE_FLOW_HASH_FLD_UDP_SRC_PORT ||
259362306a36Sopenharmony_ci	    hash_flds & ICE_FLOW_HASH_FLD_SCTP_SRC_PORT)
259462306a36Sopenharmony_ci		nfc->data |= (u64)RXH_L4_B_0_1;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	if (hash_flds & ICE_FLOW_HASH_FLD_TCP_DST_PORT ||
259762306a36Sopenharmony_ci	    hash_flds & ICE_FLOW_HASH_FLD_UDP_DST_PORT ||
259862306a36Sopenharmony_ci	    hash_flds & ICE_FLOW_HASH_FLD_SCTP_DST_PORT)
259962306a36Sopenharmony_ci		nfc->data |= (u64)RXH_L4_B_2_3;
260062306a36Sopenharmony_ci}
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci/**
260362306a36Sopenharmony_ci * ice_set_rxnfc - command to set Rx flow rules.
260462306a36Sopenharmony_ci * @netdev: network interface device structure
260562306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
260662306a36Sopenharmony_ci *
260762306a36Sopenharmony_ci * Returns 0 for success and negative values for errors
260862306a36Sopenharmony_ci */
260962306a36Sopenharmony_cistatic int ice_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
261062306a36Sopenharmony_ci{
261162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
261262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	switch (cmd->cmd) {
261562306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
261662306a36Sopenharmony_ci		return ice_add_fdir_ethtool(vsi, cmd);
261762306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
261862306a36Sopenharmony_ci		return ice_del_fdir_ethtool(vsi, cmd);
261962306a36Sopenharmony_ci	case ETHTOOL_SRXFH:
262062306a36Sopenharmony_ci		return ice_set_rss_hash_opt(vsi, cmd);
262162306a36Sopenharmony_ci	default:
262262306a36Sopenharmony_ci		break;
262362306a36Sopenharmony_ci	}
262462306a36Sopenharmony_ci	return -EOPNOTSUPP;
262562306a36Sopenharmony_ci}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci/**
262862306a36Sopenharmony_ci * ice_get_rxnfc - command to get Rx flow classification rules
262962306a36Sopenharmony_ci * @netdev: network interface device structure
263062306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
263162306a36Sopenharmony_ci * @rule_locs: buffer to rturn Rx flow classification rules
263262306a36Sopenharmony_ci *
263362306a36Sopenharmony_ci * Returns Success if the command is supported.
263462306a36Sopenharmony_ci */
263562306a36Sopenharmony_cistatic int
263662306a36Sopenharmony_ciice_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
263762306a36Sopenharmony_ci	      u32 __always_unused *rule_locs)
263862306a36Sopenharmony_ci{
263962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
264062306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
264162306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
264262306a36Sopenharmony_ci	struct ice_hw *hw;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	hw = &vsi->back->hw;
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	switch (cmd->cmd) {
264762306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
264862306a36Sopenharmony_ci		cmd->data = vsi->rss_size;
264962306a36Sopenharmony_ci		ret = 0;
265062306a36Sopenharmony_ci		break;
265162306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
265262306a36Sopenharmony_ci		cmd->rule_cnt = hw->fdir_active_fltr;
265362306a36Sopenharmony_ci		/* report total rule count */
265462306a36Sopenharmony_ci		cmd->data = ice_get_fdir_cnt_all(hw);
265562306a36Sopenharmony_ci		ret = 0;
265662306a36Sopenharmony_ci		break;
265762306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
265862306a36Sopenharmony_ci		ret = ice_get_ethtool_fdir_entry(hw, cmd);
265962306a36Sopenharmony_ci		break;
266062306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
266162306a36Sopenharmony_ci		ret = ice_get_fdir_fltr_ids(hw, cmd, (u32 *)rule_locs);
266262306a36Sopenharmony_ci		break;
266362306a36Sopenharmony_ci	case ETHTOOL_GRXFH:
266462306a36Sopenharmony_ci		ice_get_rss_hash_opt(vsi, cmd);
266562306a36Sopenharmony_ci		ret = 0;
266662306a36Sopenharmony_ci		break;
266762306a36Sopenharmony_ci	default:
266862306a36Sopenharmony_ci		break;
266962306a36Sopenharmony_ci	}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	return ret;
267262306a36Sopenharmony_ci}
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_cistatic void
267562306a36Sopenharmony_ciice_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
267662306a36Sopenharmony_ci		  struct kernel_ethtool_ringparam *kernel_ring,
267762306a36Sopenharmony_ci		  struct netlink_ext_ack *extack)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
268062306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	ring->rx_max_pending = ICE_MAX_NUM_DESC;
268362306a36Sopenharmony_ci	ring->tx_max_pending = ICE_MAX_NUM_DESC;
268462306a36Sopenharmony_ci	if (vsi->tx_rings && vsi->rx_rings) {
268562306a36Sopenharmony_ci		ring->rx_pending = vsi->rx_rings[0]->count;
268662306a36Sopenharmony_ci		ring->tx_pending = vsi->tx_rings[0]->count;
268762306a36Sopenharmony_ci	} else {
268862306a36Sopenharmony_ci		ring->rx_pending = 0;
268962306a36Sopenharmony_ci		ring->tx_pending = 0;
269062306a36Sopenharmony_ci	}
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	/* Rx mini and jumbo rings are not supported */
269362306a36Sopenharmony_ci	ring->rx_mini_max_pending = 0;
269462306a36Sopenharmony_ci	ring->rx_jumbo_max_pending = 0;
269562306a36Sopenharmony_ci	ring->rx_mini_pending = 0;
269662306a36Sopenharmony_ci	ring->rx_jumbo_pending = 0;
269762306a36Sopenharmony_ci}
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_cistatic int
270062306a36Sopenharmony_ciice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,
270162306a36Sopenharmony_ci		  struct kernel_ethtool_ringparam *kernel_ring,
270262306a36Sopenharmony_ci		  struct netlink_ext_ack *extack)
270362306a36Sopenharmony_ci{
270462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
270562306a36Sopenharmony_ci	struct ice_tx_ring *xdp_rings = NULL;
270662306a36Sopenharmony_ci	struct ice_tx_ring *tx_rings = NULL;
270762306a36Sopenharmony_ci	struct ice_rx_ring *rx_rings = NULL;
270862306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
270962306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
271062306a36Sopenharmony_ci	int i, timeout = 50, err = 0;
271162306a36Sopenharmony_ci	u16 new_rx_cnt, new_tx_cnt;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	if (ring->tx_pending > ICE_MAX_NUM_DESC ||
271462306a36Sopenharmony_ci	    ring->tx_pending < ICE_MIN_NUM_DESC ||
271562306a36Sopenharmony_ci	    ring->rx_pending > ICE_MAX_NUM_DESC ||
271662306a36Sopenharmony_ci	    ring->rx_pending < ICE_MIN_NUM_DESC) {
271762306a36Sopenharmony_ci		netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",
271862306a36Sopenharmony_ci			   ring->tx_pending, ring->rx_pending,
271962306a36Sopenharmony_ci			   ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC,
272062306a36Sopenharmony_ci			   ICE_REQ_DESC_MULTIPLE);
272162306a36Sopenharmony_ci		return -EINVAL;
272262306a36Sopenharmony_ci	}
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	/* Return if there is no rings (device is reloading) */
272562306a36Sopenharmony_ci	if (!vsi->tx_rings || !vsi->rx_rings)
272662306a36Sopenharmony_ci		return -EBUSY;
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE);
272962306a36Sopenharmony_ci	if (new_tx_cnt != ring->tx_pending)
273062306a36Sopenharmony_ci		netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n",
273162306a36Sopenharmony_ci			    new_tx_cnt);
273262306a36Sopenharmony_ci	new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE);
273362306a36Sopenharmony_ci	if (new_rx_cnt != ring->rx_pending)
273462306a36Sopenharmony_ci		netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n",
273562306a36Sopenharmony_ci			    new_rx_cnt);
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci	/* if nothing to do return success */
273862306a36Sopenharmony_ci	if (new_tx_cnt == vsi->tx_rings[0]->count &&
273962306a36Sopenharmony_ci	    new_rx_cnt == vsi->rx_rings[0]->count) {
274062306a36Sopenharmony_ci		netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n");
274162306a36Sopenharmony_ci		return 0;
274262306a36Sopenharmony_ci	}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	/* If there is a AF_XDP UMEM attached to any of Rx rings,
274562306a36Sopenharmony_ci	 * disallow changing the number of descriptors -- regardless
274662306a36Sopenharmony_ci	 * if the netdev is running or not.
274762306a36Sopenharmony_ci	 */
274862306a36Sopenharmony_ci	if (ice_xsk_any_rx_ring_ena(vsi))
274962306a36Sopenharmony_ci		return -EBUSY;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	while (test_and_set_bit(ICE_CFG_BUSY, pf->state)) {
275262306a36Sopenharmony_ci		timeout--;
275362306a36Sopenharmony_ci		if (!timeout)
275462306a36Sopenharmony_ci			return -EBUSY;
275562306a36Sopenharmony_ci		usleep_range(1000, 2000);
275662306a36Sopenharmony_ci	}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	/* set for the next time the netdev is started */
275962306a36Sopenharmony_ci	if (!netif_running(vsi->netdev)) {
276062306a36Sopenharmony_ci		ice_for_each_alloc_txq(vsi, i)
276162306a36Sopenharmony_ci			vsi->tx_rings[i]->count = new_tx_cnt;
276262306a36Sopenharmony_ci		ice_for_each_alloc_rxq(vsi, i)
276362306a36Sopenharmony_ci			vsi->rx_rings[i]->count = new_rx_cnt;
276462306a36Sopenharmony_ci		if (ice_is_xdp_ena_vsi(vsi))
276562306a36Sopenharmony_ci			ice_for_each_xdp_txq(vsi, i)
276662306a36Sopenharmony_ci				vsi->xdp_rings[i]->count = new_tx_cnt;
276762306a36Sopenharmony_ci		vsi->num_tx_desc = (u16)new_tx_cnt;
276862306a36Sopenharmony_ci		vsi->num_rx_desc = (u16)new_rx_cnt;
276962306a36Sopenharmony_ci		netdev_dbg(netdev, "Link is down, descriptor count change happens when link is brought up\n");
277062306a36Sopenharmony_ci		goto done;
277162306a36Sopenharmony_ci	}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	if (new_tx_cnt == vsi->tx_rings[0]->count)
277462306a36Sopenharmony_ci		goto process_rx;
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	/* alloc updated Tx resources */
277762306a36Sopenharmony_ci	netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n",
277862306a36Sopenharmony_ci		    vsi->tx_rings[0]->count, new_tx_cnt);
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	tx_rings = kcalloc(vsi->num_txq, sizeof(*tx_rings), GFP_KERNEL);
278162306a36Sopenharmony_ci	if (!tx_rings) {
278262306a36Sopenharmony_ci		err = -ENOMEM;
278362306a36Sopenharmony_ci		goto done;
278462306a36Sopenharmony_ci	}
278562306a36Sopenharmony_ci
278662306a36Sopenharmony_ci	ice_for_each_txq(vsi, i) {
278762306a36Sopenharmony_ci		/* clone ring and setup updated count */
278862306a36Sopenharmony_ci		tx_rings[i] = *vsi->tx_rings[i];
278962306a36Sopenharmony_ci		tx_rings[i].count = new_tx_cnt;
279062306a36Sopenharmony_ci		tx_rings[i].desc = NULL;
279162306a36Sopenharmony_ci		tx_rings[i].tx_buf = NULL;
279262306a36Sopenharmony_ci		tx_rings[i].tx_tstamps = &pf->ptp.port.tx;
279362306a36Sopenharmony_ci		err = ice_setup_tx_ring(&tx_rings[i]);
279462306a36Sopenharmony_ci		if (err) {
279562306a36Sopenharmony_ci			while (i--)
279662306a36Sopenharmony_ci				ice_clean_tx_ring(&tx_rings[i]);
279762306a36Sopenharmony_ci			kfree(tx_rings);
279862306a36Sopenharmony_ci			goto done;
279962306a36Sopenharmony_ci		}
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	if (!ice_is_xdp_ena_vsi(vsi))
280362306a36Sopenharmony_ci		goto process_rx;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	/* alloc updated XDP resources */
280662306a36Sopenharmony_ci	netdev_info(netdev, "Changing XDP descriptor count from %d to %d\n",
280762306a36Sopenharmony_ci		    vsi->xdp_rings[0]->count, new_tx_cnt);
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	xdp_rings = kcalloc(vsi->num_xdp_txq, sizeof(*xdp_rings), GFP_KERNEL);
281062306a36Sopenharmony_ci	if (!xdp_rings) {
281162306a36Sopenharmony_ci		err = -ENOMEM;
281262306a36Sopenharmony_ci		goto free_tx;
281362306a36Sopenharmony_ci	}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	ice_for_each_xdp_txq(vsi, i) {
281662306a36Sopenharmony_ci		/* clone ring and setup updated count */
281762306a36Sopenharmony_ci		xdp_rings[i] = *vsi->xdp_rings[i];
281862306a36Sopenharmony_ci		xdp_rings[i].count = new_tx_cnt;
281962306a36Sopenharmony_ci		xdp_rings[i].desc = NULL;
282062306a36Sopenharmony_ci		xdp_rings[i].tx_buf = NULL;
282162306a36Sopenharmony_ci		err = ice_setup_tx_ring(&xdp_rings[i]);
282262306a36Sopenharmony_ci		if (err) {
282362306a36Sopenharmony_ci			while (i--)
282462306a36Sopenharmony_ci				ice_clean_tx_ring(&xdp_rings[i]);
282562306a36Sopenharmony_ci			kfree(xdp_rings);
282662306a36Sopenharmony_ci			goto free_tx;
282762306a36Sopenharmony_ci		}
282862306a36Sopenharmony_ci		ice_set_ring_xdp(&xdp_rings[i]);
282962306a36Sopenharmony_ci	}
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ciprocess_rx:
283262306a36Sopenharmony_ci	if (new_rx_cnt == vsi->rx_rings[0]->count)
283362306a36Sopenharmony_ci		goto process_link;
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	/* alloc updated Rx resources */
283662306a36Sopenharmony_ci	netdev_info(netdev, "Changing Rx descriptor count from %d to %d\n",
283762306a36Sopenharmony_ci		    vsi->rx_rings[0]->count, new_rx_cnt);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	rx_rings = kcalloc(vsi->num_rxq, sizeof(*rx_rings), GFP_KERNEL);
284062306a36Sopenharmony_ci	if (!rx_rings) {
284162306a36Sopenharmony_ci		err = -ENOMEM;
284262306a36Sopenharmony_ci		goto done;
284362306a36Sopenharmony_ci	}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i) {
284662306a36Sopenharmony_ci		/* clone ring and setup updated count */
284762306a36Sopenharmony_ci		rx_rings[i] = *vsi->rx_rings[i];
284862306a36Sopenharmony_ci		rx_rings[i].count = new_rx_cnt;
284962306a36Sopenharmony_ci		rx_rings[i].cached_phctime = pf->ptp.cached_phc_time;
285062306a36Sopenharmony_ci		rx_rings[i].desc = NULL;
285162306a36Sopenharmony_ci		rx_rings[i].rx_buf = NULL;
285262306a36Sopenharmony_ci		/* this is to allow wr32 to have something to write to
285362306a36Sopenharmony_ci		 * during early allocation of Rx buffers
285462306a36Sopenharmony_ci		 */
285562306a36Sopenharmony_ci		rx_rings[i].tail = vsi->back->hw.hw_addr + PRTGEN_STATUS;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci		err = ice_setup_rx_ring(&rx_rings[i]);
285862306a36Sopenharmony_ci		if (err)
285962306a36Sopenharmony_ci			goto rx_unwind;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci		/* allocate Rx buffers */
286262306a36Sopenharmony_ci		err = ice_alloc_rx_bufs(&rx_rings[i],
286362306a36Sopenharmony_ci					ICE_RX_DESC_UNUSED(&rx_rings[i]));
286462306a36Sopenharmony_cirx_unwind:
286562306a36Sopenharmony_ci		if (err) {
286662306a36Sopenharmony_ci			while (i) {
286762306a36Sopenharmony_ci				i--;
286862306a36Sopenharmony_ci				ice_free_rx_ring(&rx_rings[i]);
286962306a36Sopenharmony_ci			}
287062306a36Sopenharmony_ci			kfree(rx_rings);
287162306a36Sopenharmony_ci			err = -ENOMEM;
287262306a36Sopenharmony_ci			goto free_tx;
287362306a36Sopenharmony_ci		}
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ciprocess_link:
287762306a36Sopenharmony_ci	/* Bring interface down, copy in the new ring info, then restore the
287862306a36Sopenharmony_ci	 * interface. if VSI is up, bring it down and then back up
287962306a36Sopenharmony_ci	 */
288062306a36Sopenharmony_ci	if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
288162306a36Sopenharmony_ci		ice_down(vsi);
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci		if (tx_rings) {
288462306a36Sopenharmony_ci			ice_for_each_txq(vsi, i) {
288562306a36Sopenharmony_ci				ice_free_tx_ring(vsi->tx_rings[i]);
288662306a36Sopenharmony_ci				*vsi->tx_rings[i] = tx_rings[i];
288762306a36Sopenharmony_ci			}
288862306a36Sopenharmony_ci			kfree(tx_rings);
288962306a36Sopenharmony_ci		}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci		if (rx_rings) {
289262306a36Sopenharmony_ci			ice_for_each_rxq(vsi, i) {
289362306a36Sopenharmony_ci				ice_free_rx_ring(vsi->rx_rings[i]);
289462306a36Sopenharmony_ci				/* copy the real tail offset */
289562306a36Sopenharmony_ci				rx_rings[i].tail = vsi->rx_rings[i]->tail;
289662306a36Sopenharmony_ci				/* this is to fake out the allocation routine
289762306a36Sopenharmony_ci				 * into thinking it has to realloc everything
289862306a36Sopenharmony_ci				 * but the recycling logic will let us re-use
289962306a36Sopenharmony_ci				 * the buffers allocated above
290062306a36Sopenharmony_ci				 */
290162306a36Sopenharmony_ci				rx_rings[i].next_to_use = 0;
290262306a36Sopenharmony_ci				rx_rings[i].next_to_clean = 0;
290362306a36Sopenharmony_ci				rx_rings[i].next_to_alloc = 0;
290462306a36Sopenharmony_ci				*vsi->rx_rings[i] = rx_rings[i];
290562306a36Sopenharmony_ci			}
290662306a36Sopenharmony_ci			kfree(rx_rings);
290762306a36Sopenharmony_ci		}
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci		if (xdp_rings) {
291062306a36Sopenharmony_ci			ice_for_each_xdp_txq(vsi, i) {
291162306a36Sopenharmony_ci				ice_free_tx_ring(vsi->xdp_rings[i]);
291262306a36Sopenharmony_ci				*vsi->xdp_rings[i] = xdp_rings[i];
291362306a36Sopenharmony_ci			}
291462306a36Sopenharmony_ci			kfree(xdp_rings);
291562306a36Sopenharmony_ci		}
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci		vsi->num_tx_desc = new_tx_cnt;
291862306a36Sopenharmony_ci		vsi->num_rx_desc = new_rx_cnt;
291962306a36Sopenharmony_ci		ice_up(vsi);
292062306a36Sopenharmony_ci	}
292162306a36Sopenharmony_ci	goto done;
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_cifree_tx:
292462306a36Sopenharmony_ci	/* error cleanup if the Rx allocations failed after getting Tx */
292562306a36Sopenharmony_ci	if (tx_rings) {
292662306a36Sopenharmony_ci		ice_for_each_txq(vsi, i)
292762306a36Sopenharmony_ci			ice_free_tx_ring(&tx_rings[i]);
292862306a36Sopenharmony_ci		kfree(tx_rings);
292962306a36Sopenharmony_ci	}
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_cidone:
293262306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, pf->state);
293362306a36Sopenharmony_ci	return err;
293462306a36Sopenharmony_ci}
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci/**
293762306a36Sopenharmony_ci * ice_get_pauseparam - Get Flow Control status
293862306a36Sopenharmony_ci * @netdev: network interface device structure
293962306a36Sopenharmony_ci * @pause: ethernet pause (flow control) parameters
294062306a36Sopenharmony_ci *
294162306a36Sopenharmony_ci * Get requested flow control status from PHY capability.
294262306a36Sopenharmony_ci * If autoneg is true, then ethtool will send the ETHTOOL_GSET ioctl which
294362306a36Sopenharmony_ci * is handled by ice_get_link_ksettings. ice_get_link_ksettings will report
294462306a36Sopenharmony_ci * the negotiated Rx/Tx pause via lp_advertising.
294562306a36Sopenharmony_ci */
294662306a36Sopenharmony_cistatic void
294762306a36Sopenharmony_ciice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
294862306a36Sopenharmony_ci{
294962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
295062306a36Sopenharmony_ci	struct ice_port_info *pi = np->vsi->port_info;
295162306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *pcaps;
295262306a36Sopenharmony_ci	struct ice_dcbx_cfg *dcbx_cfg;
295362306a36Sopenharmony_ci	int status;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci	/* Initialize pause params */
295662306a36Sopenharmony_ci	pause->rx_pause = 0;
295762306a36Sopenharmony_ci	pause->tx_pause = 0;
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
296262306a36Sopenharmony_ci	if (!pcaps)
296362306a36Sopenharmony_ci		return;
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	/* Get current PHY config */
296662306a36Sopenharmony_ci	status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
296762306a36Sopenharmony_ci				     NULL);
296862306a36Sopenharmony_ci	if (status)
296962306a36Sopenharmony_ci		goto out;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	pause->autoneg = ice_is_phy_caps_an_enabled(pcaps) ? AUTONEG_ENABLE :
297262306a36Sopenharmony_ci							     AUTONEG_DISABLE;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	if (dcbx_cfg->pfc.pfcena)
297562306a36Sopenharmony_ci		/* PFC enabled so report LFC as off */
297662306a36Sopenharmony_ci		goto out;
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	if (pcaps->caps & ICE_AQC_PHY_EN_TX_LINK_PAUSE)
297962306a36Sopenharmony_ci		pause->tx_pause = 1;
298062306a36Sopenharmony_ci	if (pcaps->caps & ICE_AQC_PHY_EN_RX_LINK_PAUSE)
298162306a36Sopenharmony_ci		pause->rx_pause = 1;
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ciout:
298462306a36Sopenharmony_ci	kfree(pcaps);
298562306a36Sopenharmony_ci}
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci/**
298862306a36Sopenharmony_ci * ice_set_pauseparam - Set Flow Control parameter
298962306a36Sopenharmony_ci * @netdev: network interface device structure
299062306a36Sopenharmony_ci * @pause: return Tx/Rx flow control status
299162306a36Sopenharmony_ci */
299262306a36Sopenharmony_cistatic int
299362306a36Sopenharmony_ciice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)
299462306a36Sopenharmony_ci{
299562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
299662306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *pcaps;
299762306a36Sopenharmony_ci	struct ice_link_status *hw_link_info;
299862306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
299962306a36Sopenharmony_ci	struct ice_dcbx_cfg *dcbx_cfg;
300062306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
300162306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
300262306a36Sopenharmony_ci	struct ice_port_info *pi;
300362306a36Sopenharmony_ci	u8 aq_failures;
300462306a36Sopenharmony_ci	bool link_up;
300562306a36Sopenharmony_ci	u32 is_an;
300662306a36Sopenharmony_ci	int err;
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	pi = vsi->port_info;
300962306a36Sopenharmony_ci	hw_link_info = &pi->phy.link_info;
301062306a36Sopenharmony_ci	dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
301162306a36Sopenharmony_ci	link_up = hw_link_info->link_info & ICE_AQ_LINK_UP;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	/* Changing the port's flow control is not supported if this isn't the
301462306a36Sopenharmony_ci	 * PF VSI
301562306a36Sopenharmony_ci	 */
301662306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF) {
301762306a36Sopenharmony_ci		netdev_info(netdev, "Changing flow control parameters only supported for PF VSI\n");
301862306a36Sopenharmony_ci		return -EOPNOTSUPP;
301962306a36Sopenharmony_ci	}
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci	/* Get pause param reports configured and negotiated flow control pause
302262306a36Sopenharmony_ci	 * when ETHTOOL_GLINKSETTINGS is defined. Since ETHTOOL_GLINKSETTINGS is
302362306a36Sopenharmony_ci	 * defined get pause param pause->autoneg reports SW configured setting,
302462306a36Sopenharmony_ci	 * so compare pause->autoneg with SW configured to prevent the user from
302562306a36Sopenharmony_ci	 * using set pause param to chance autoneg.
302662306a36Sopenharmony_ci	 */
302762306a36Sopenharmony_ci	pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
302862306a36Sopenharmony_ci	if (!pcaps)
302962306a36Sopenharmony_ci		return -ENOMEM;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	/* Get current PHY config */
303262306a36Sopenharmony_ci	err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
303362306a36Sopenharmony_ci				  NULL);
303462306a36Sopenharmony_ci	if (err) {
303562306a36Sopenharmony_ci		kfree(pcaps);
303662306a36Sopenharmony_ci		return err;
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	is_an = ice_is_phy_caps_an_enabled(pcaps) ? AUTONEG_ENABLE :
304062306a36Sopenharmony_ci						    AUTONEG_DISABLE;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	kfree(pcaps);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	if (pause->autoneg != is_an) {
304562306a36Sopenharmony_ci		netdev_info(netdev, "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
304662306a36Sopenharmony_ci		return -EOPNOTSUPP;
304762306a36Sopenharmony_ci	}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	/* If we have link and don't have autoneg */
305062306a36Sopenharmony_ci	if (!test_bit(ICE_DOWN, pf->state) &&
305162306a36Sopenharmony_ci	    !(hw_link_info->an_info & ICE_AQ_AN_COMPLETED)) {
305262306a36Sopenharmony_ci		/* Send message that it might not necessarily work*/
305362306a36Sopenharmony_ci		netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n");
305462306a36Sopenharmony_ci	}
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	if (dcbx_cfg->pfc.pfcena) {
305762306a36Sopenharmony_ci		netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n");
305862306a36Sopenharmony_ci		return -EOPNOTSUPP;
305962306a36Sopenharmony_ci	}
306062306a36Sopenharmony_ci	if (pause->rx_pause && pause->tx_pause)
306162306a36Sopenharmony_ci		pi->fc.req_mode = ICE_FC_FULL;
306262306a36Sopenharmony_ci	else if (pause->rx_pause && !pause->tx_pause)
306362306a36Sopenharmony_ci		pi->fc.req_mode = ICE_FC_RX_PAUSE;
306462306a36Sopenharmony_ci	else if (!pause->rx_pause && pause->tx_pause)
306562306a36Sopenharmony_ci		pi->fc.req_mode = ICE_FC_TX_PAUSE;
306662306a36Sopenharmony_ci	else if (!pause->rx_pause && !pause->tx_pause)
306762306a36Sopenharmony_ci		pi->fc.req_mode = ICE_FC_NONE;
306862306a36Sopenharmony_ci	else
306962306a36Sopenharmony_ci		return -EINVAL;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	/* Set the FC mode and only restart AN if link is up */
307262306a36Sopenharmony_ci	err = ice_set_fc(pi, &aq_failures, link_up);
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) {
307562306a36Sopenharmony_ci		netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n",
307662306a36Sopenharmony_ci			    err, ice_aq_str(hw->adminq.sq_last_status));
307762306a36Sopenharmony_ci		err = -EAGAIN;
307862306a36Sopenharmony_ci	} else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) {
307962306a36Sopenharmony_ci		netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n",
308062306a36Sopenharmony_ci			    err, ice_aq_str(hw->adminq.sq_last_status));
308162306a36Sopenharmony_ci		err = -EAGAIN;
308262306a36Sopenharmony_ci	} else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) {
308362306a36Sopenharmony_ci		netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n",
308462306a36Sopenharmony_ci			    err, ice_aq_str(hw->adminq.sq_last_status));
308562306a36Sopenharmony_ci		err = -EAGAIN;
308662306a36Sopenharmony_ci	}
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	return err;
308962306a36Sopenharmony_ci}
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci/**
309262306a36Sopenharmony_ci * ice_get_rxfh_key_size - get the RSS hash key size
309362306a36Sopenharmony_ci * @netdev: network interface device structure
309462306a36Sopenharmony_ci *
309562306a36Sopenharmony_ci * Returns the table size.
309662306a36Sopenharmony_ci */
309762306a36Sopenharmony_cistatic u32 ice_get_rxfh_key_size(struct net_device __always_unused *netdev)
309862306a36Sopenharmony_ci{
309962306a36Sopenharmony_ci	return ICE_VSIQF_HKEY_ARRAY_SIZE;
310062306a36Sopenharmony_ci}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci/**
310362306a36Sopenharmony_ci * ice_get_rxfh_indir_size - get the Rx flow hash indirection table size
310462306a36Sopenharmony_ci * @netdev: network interface device structure
310562306a36Sopenharmony_ci *
310662306a36Sopenharmony_ci * Returns the table size.
310762306a36Sopenharmony_ci */
310862306a36Sopenharmony_cistatic u32 ice_get_rxfh_indir_size(struct net_device *netdev)
310962306a36Sopenharmony_ci{
311062306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci	return np->vsi->rss_table_size;
311362306a36Sopenharmony_ci}
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_cistatic int
311662306a36Sopenharmony_ciice_get_rxfh_context(struct net_device *netdev, u32 *indir,
311762306a36Sopenharmony_ci		     u8 *key, u8 *hfunc, u32 rss_context)
311862306a36Sopenharmony_ci{
311962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
312062306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
312162306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
312262306a36Sopenharmony_ci	u16 qcount, offset;
312362306a36Sopenharmony_ci	int err, num_tc, i;
312462306a36Sopenharmony_ci	u8 *lut;
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
312762306a36Sopenharmony_ci		netdev_warn(netdev, "RSS is not supported on this VSI!\n");
312862306a36Sopenharmony_ci		return -EOPNOTSUPP;
312962306a36Sopenharmony_ci	}
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	if (rss_context && !ice_is_adq_active(pf)) {
313262306a36Sopenharmony_ci		netdev_err(netdev, "RSS context cannot be non-zero when ADQ is not configured.\n");
313362306a36Sopenharmony_ci		return -EINVAL;
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	qcount = vsi->mqprio_qopt.qopt.count[rss_context];
313762306a36Sopenharmony_ci	offset = vsi->mqprio_qopt.qopt.offset[rss_context];
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	if (rss_context && ice_is_adq_active(pf)) {
314062306a36Sopenharmony_ci		num_tc = vsi->mqprio_qopt.qopt.num_tc;
314162306a36Sopenharmony_ci		if (rss_context >= num_tc) {
314262306a36Sopenharmony_ci			netdev_err(netdev, "RSS context:%d  > num_tc:%d\n",
314362306a36Sopenharmony_ci				   rss_context, num_tc);
314462306a36Sopenharmony_ci			return -EINVAL;
314562306a36Sopenharmony_ci		}
314662306a36Sopenharmony_ci		/* Use channel VSI of given TC */
314762306a36Sopenharmony_ci		vsi = vsi->tc_map_vsi[rss_context];
314862306a36Sopenharmony_ci	}
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci	if (hfunc)
315162306a36Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	if (!indir)
315462306a36Sopenharmony_ci		return 0;
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
315762306a36Sopenharmony_ci	if (!lut)
315862306a36Sopenharmony_ci		return -ENOMEM;
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	err = ice_get_rss_key(vsi, key);
316162306a36Sopenharmony_ci	if (err)
316262306a36Sopenharmony_ci		goto out;
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	err = ice_get_rss_lut(vsi, lut, vsi->rss_table_size);
316562306a36Sopenharmony_ci	if (err)
316662306a36Sopenharmony_ci		goto out;
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	if (ice_is_adq_active(pf)) {
316962306a36Sopenharmony_ci		for (i = 0; i < vsi->rss_table_size; i++)
317062306a36Sopenharmony_ci			indir[i] = offset + lut[i] % qcount;
317162306a36Sopenharmony_ci		goto out;
317262306a36Sopenharmony_ci	}
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	for (i = 0; i < vsi->rss_table_size; i++)
317562306a36Sopenharmony_ci		indir[i] = lut[i];
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ciout:
317862306a36Sopenharmony_ci	kfree(lut);
317962306a36Sopenharmony_ci	return err;
318062306a36Sopenharmony_ci}
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci/**
318362306a36Sopenharmony_ci * ice_get_rxfh - get the Rx flow hash indirection table
318462306a36Sopenharmony_ci * @netdev: network interface device structure
318562306a36Sopenharmony_ci * @indir: indirection table
318662306a36Sopenharmony_ci * @key: hash key
318762306a36Sopenharmony_ci * @hfunc: hash function
318862306a36Sopenharmony_ci *
318962306a36Sopenharmony_ci * Reads the indirection table directly from the hardware.
319062306a36Sopenharmony_ci */
319162306a36Sopenharmony_cistatic int
319262306a36Sopenharmony_ciice_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
319362306a36Sopenharmony_ci{
319462306a36Sopenharmony_ci	return ice_get_rxfh_context(netdev, indir, key, hfunc, 0);
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci/**
319862306a36Sopenharmony_ci * ice_set_rxfh - set the Rx flow hash indirection table
319962306a36Sopenharmony_ci * @netdev: network interface device structure
320062306a36Sopenharmony_ci * @indir: indirection table
320162306a36Sopenharmony_ci * @key: hash key
320262306a36Sopenharmony_ci * @hfunc: hash function
320362306a36Sopenharmony_ci *
320462306a36Sopenharmony_ci * Returns -EINVAL if the table specifies an invalid queue ID, otherwise
320562306a36Sopenharmony_ci * returns 0 after programming the table.
320662306a36Sopenharmony_ci */
320762306a36Sopenharmony_cistatic int
320862306a36Sopenharmony_ciice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
320962306a36Sopenharmony_ci	     const u8 hfunc)
321062306a36Sopenharmony_ci{
321162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
321262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
321362306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
321462306a36Sopenharmony_ci	struct device *dev;
321562306a36Sopenharmony_ci	int err;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
321862306a36Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
321962306a36Sopenharmony_ci		return -EOPNOTSUPP;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
322262306a36Sopenharmony_ci		/* RSS not supported return error here */
322362306a36Sopenharmony_ci		netdev_warn(netdev, "RSS is not configured on this VSI!\n");
322462306a36Sopenharmony_ci		return -EIO;
322562306a36Sopenharmony_ci	}
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	if (ice_is_adq_active(pf)) {
322862306a36Sopenharmony_ci		netdev_err(netdev, "Cannot change RSS params with ADQ configured.\n");
322962306a36Sopenharmony_ci		return -EOPNOTSUPP;
323062306a36Sopenharmony_ci	}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	if (key) {
323362306a36Sopenharmony_ci		if (!vsi->rss_hkey_user) {
323462306a36Sopenharmony_ci			vsi->rss_hkey_user =
323562306a36Sopenharmony_ci				devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE,
323662306a36Sopenharmony_ci					     GFP_KERNEL);
323762306a36Sopenharmony_ci			if (!vsi->rss_hkey_user)
323862306a36Sopenharmony_ci				return -ENOMEM;
323962306a36Sopenharmony_ci		}
324062306a36Sopenharmony_ci		memcpy(vsi->rss_hkey_user, key, ICE_VSIQF_HKEY_ARRAY_SIZE);
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci		err = ice_set_rss_key(vsi, vsi->rss_hkey_user);
324362306a36Sopenharmony_ci		if (err)
324462306a36Sopenharmony_ci			return err;
324562306a36Sopenharmony_ci	}
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	if (!vsi->rss_lut_user) {
324862306a36Sopenharmony_ci		vsi->rss_lut_user = devm_kzalloc(dev, vsi->rss_table_size,
324962306a36Sopenharmony_ci						 GFP_KERNEL);
325062306a36Sopenharmony_ci		if (!vsi->rss_lut_user)
325162306a36Sopenharmony_ci			return -ENOMEM;
325262306a36Sopenharmony_ci	}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	/* Each 32 bits pointed by 'indir' is stored with a lut entry */
325562306a36Sopenharmony_ci	if (indir) {
325662306a36Sopenharmony_ci		int i;
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci		for (i = 0; i < vsi->rss_table_size; i++)
325962306a36Sopenharmony_ci			vsi->rss_lut_user[i] = (u8)(indir[i]);
326062306a36Sopenharmony_ci	} else {
326162306a36Sopenharmony_ci		ice_fill_rss_lut(vsi->rss_lut_user, vsi->rss_table_size,
326262306a36Sopenharmony_ci				 vsi->rss_size);
326362306a36Sopenharmony_ci	}
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	err = ice_set_rss_lut(vsi, vsi->rss_lut_user, vsi->rss_table_size);
326662306a36Sopenharmony_ci	if (err)
326762306a36Sopenharmony_ci		return err;
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	return 0;
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_cistatic int
327362306a36Sopenharmony_ciice_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
327462306a36Sopenharmony_ci{
327562306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(dev);
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	/* only report timestamping if PTP is enabled */
327862306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_PTP, pf->flags))
327962306a36Sopenharmony_ci		return ethtool_op_get_ts_info(dev, info);
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
328262306a36Sopenharmony_ci				SOF_TIMESTAMPING_RX_SOFTWARE |
328362306a36Sopenharmony_ci				SOF_TIMESTAMPING_SOFTWARE |
328462306a36Sopenharmony_ci				SOF_TIMESTAMPING_TX_HARDWARE |
328562306a36Sopenharmony_ci				SOF_TIMESTAMPING_RX_HARDWARE |
328662306a36Sopenharmony_ci				SOF_TIMESTAMPING_RAW_HARDWARE;
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	info->phc_index = ice_get_ptp_clock_index(pf);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_ci	return 0;
329562306a36Sopenharmony_ci}
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci/**
329862306a36Sopenharmony_ci * ice_get_max_txq - return the maximum number of Tx queues for in a PF
329962306a36Sopenharmony_ci * @pf: PF structure
330062306a36Sopenharmony_ci */
330162306a36Sopenharmony_cistatic int ice_get_max_txq(struct ice_pf *pf)
330262306a36Sopenharmony_ci{
330362306a36Sopenharmony_ci	return min3(pf->num_lan_msix, (u16)num_online_cpus(),
330462306a36Sopenharmony_ci		    (u16)pf->hw.func_caps.common_cap.num_txq);
330562306a36Sopenharmony_ci}
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci/**
330862306a36Sopenharmony_ci * ice_get_max_rxq - return the maximum number of Rx queues for in a PF
330962306a36Sopenharmony_ci * @pf: PF structure
331062306a36Sopenharmony_ci */
331162306a36Sopenharmony_cistatic int ice_get_max_rxq(struct ice_pf *pf)
331262306a36Sopenharmony_ci{
331362306a36Sopenharmony_ci	return min3(pf->num_lan_msix, (u16)num_online_cpus(),
331462306a36Sopenharmony_ci		    (u16)pf->hw.func_caps.common_cap.num_rxq);
331562306a36Sopenharmony_ci}
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci/**
331862306a36Sopenharmony_ci * ice_get_combined_cnt - return the current number of combined channels
331962306a36Sopenharmony_ci * @vsi: PF VSI pointer
332062306a36Sopenharmony_ci *
332162306a36Sopenharmony_ci * Go through all queue vectors and count ones that have both Rx and Tx ring
332262306a36Sopenharmony_ci * attached
332362306a36Sopenharmony_ci */
332462306a36Sopenharmony_cistatic u32 ice_get_combined_cnt(struct ice_vsi *vsi)
332562306a36Sopenharmony_ci{
332662306a36Sopenharmony_ci	u32 combined = 0;
332762306a36Sopenharmony_ci	int q_idx;
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, q_idx) {
333062306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[q_idx];
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci		if (q_vector->rx.rx_ring && q_vector->tx.tx_ring)
333362306a36Sopenharmony_ci			combined++;
333462306a36Sopenharmony_ci	}
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	return combined;
333762306a36Sopenharmony_ci}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci/**
334062306a36Sopenharmony_ci * ice_get_channels - get the current and max supported channels
334162306a36Sopenharmony_ci * @dev: network interface device structure
334262306a36Sopenharmony_ci * @ch: ethtool channel data structure
334362306a36Sopenharmony_ci */
334462306a36Sopenharmony_cistatic void
334562306a36Sopenharmony_ciice_get_channels(struct net_device *dev, struct ethtool_channels *ch)
334662306a36Sopenharmony_ci{
334762306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(dev);
334862306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
334962306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	/* report maximum channels */
335262306a36Sopenharmony_ci	ch->max_rx = ice_get_max_rxq(pf);
335362306a36Sopenharmony_ci	ch->max_tx = ice_get_max_txq(pf);
335462306a36Sopenharmony_ci	ch->max_combined = min_t(int, ch->max_rx, ch->max_tx);
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci	/* report current channels */
335762306a36Sopenharmony_ci	ch->combined_count = ice_get_combined_cnt(vsi);
335862306a36Sopenharmony_ci	ch->rx_count = vsi->num_rxq - ch->combined_count;
335962306a36Sopenharmony_ci	ch->tx_count = vsi->num_txq - ch->combined_count;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	/* report other queues */
336262306a36Sopenharmony_ci	ch->other_count = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0;
336362306a36Sopenharmony_ci	ch->max_other = ch->other_count;
336462306a36Sopenharmony_ci}
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci/**
336762306a36Sopenharmony_ci * ice_get_valid_rss_size - return valid number of RSS queues
336862306a36Sopenharmony_ci * @hw: pointer to the HW structure
336962306a36Sopenharmony_ci * @new_size: requested RSS queues
337062306a36Sopenharmony_ci */
337162306a36Sopenharmony_cistatic int ice_get_valid_rss_size(struct ice_hw *hw, int new_size)
337262306a36Sopenharmony_ci{
337362306a36Sopenharmony_ci	struct ice_hw_common_caps *caps = &hw->func_caps.common_cap;
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	return min_t(int, new_size, BIT(caps->rss_table_entry_width));
337662306a36Sopenharmony_ci}
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci/**
337962306a36Sopenharmony_ci * ice_vsi_set_dflt_rss_lut - set default RSS LUT with requested RSS size
338062306a36Sopenharmony_ci * @vsi: VSI to reconfigure RSS LUT on
338162306a36Sopenharmony_ci * @req_rss_size: requested range of queue numbers for hashing
338262306a36Sopenharmony_ci *
338362306a36Sopenharmony_ci * Set the VSI's RSS parameters, configure the RSS LUT based on these.
338462306a36Sopenharmony_ci */
338562306a36Sopenharmony_cistatic int ice_vsi_set_dflt_rss_lut(struct ice_vsi *vsi, int req_rss_size)
338662306a36Sopenharmony_ci{
338762306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
338862306a36Sopenharmony_ci	struct device *dev;
338962306a36Sopenharmony_ci	struct ice_hw *hw;
339062306a36Sopenharmony_ci	int err;
339162306a36Sopenharmony_ci	u8 *lut;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
339462306a36Sopenharmony_ci	hw = &pf->hw;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	if (!req_rss_size)
339762306a36Sopenharmony_ci		return -EINVAL;
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
340062306a36Sopenharmony_ci	if (!lut)
340162306a36Sopenharmony_ci		return -ENOMEM;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	/* set RSS LUT parameters */
340462306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags))
340562306a36Sopenharmony_ci		vsi->rss_size = 1;
340662306a36Sopenharmony_ci	else
340762306a36Sopenharmony_ci		vsi->rss_size = ice_get_valid_rss_size(hw, req_rss_size);
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	/* create/set RSS LUT */
341062306a36Sopenharmony_ci	ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size);
341162306a36Sopenharmony_ci	err = ice_set_rss_lut(vsi, lut, vsi->rss_table_size);
341262306a36Sopenharmony_ci	if (err)
341362306a36Sopenharmony_ci		dev_err(dev, "Cannot set RSS lut, err %d aq_err %s\n", err,
341462306a36Sopenharmony_ci			ice_aq_str(hw->adminq.sq_last_status));
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_ci	kfree(lut);
341762306a36Sopenharmony_ci	return err;
341862306a36Sopenharmony_ci}
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci/**
342162306a36Sopenharmony_ci * ice_set_channels - set the number channels
342262306a36Sopenharmony_ci * @dev: network interface device structure
342362306a36Sopenharmony_ci * @ch: ethtool channel data structure
342462306a36Sopenharmony_ci */
342562306a36Sopenharmony_cistatic int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)
342662306a36Sopenharmony_ci{
342762306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(dev);
342862306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
342962306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
343062306a36Sopenharmony_ci	int new_rx = 0, new_tx = 0;
343162306a36Sopenharmony_ci	bool locked = false;
343262306a36Sopenharmony_ci	u32 curr_combined;
343362306a36Sopenharmony_ci	int ret = 0;
343462306a36Sopenharmony_ci
343562306a36Sopenharmony_ci	/* do not support changing channels in Safe Mode */
343662306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
343762306a36Sopenharmony_ci		netdev_err(dev, "Changing channel in Safe Mode is not supported\n");
343862306a36Sopenharmony_ci		return -EOPNOTSUPP;
343962306a36Sopenharmony_ci	}
344062306a36Sopenharmony_ci	/* do not support changing other_count */
344162306a36Sopenharmony_ci	if (ch->other_count != (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1U : 0U))
344262306a36Sopenharmony_ci		return -EINVAL;
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	if (ice_is_adq_active(pf)) {
344562306a36Sopenharmony_ci		netdev_err(dev, "Cannot set channels with ADQ configured.\n");
344662306a36Sopenharmony_ci		return -EOPNOTSUPP;
344762306a36Sopenharmony_ci	}
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) {
345062306a36Sopenharmony_ci		netdev_err(dev, "Cannot set channels when Flow Director filters are active\n");
345162306a36Sopenharmony_ci		return -EOPNOTSUPP;
345262306a36Sopenharmony_ci	}
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	curr_combined = ice_get_combined_cnt(vsi);
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	/* these checks are for cases where user didn't specify a particular
345762306a36Sopenharmony_ci	 * value on cmd line but we get non-zero value anyway via
345862306a36Sopenharmony_ci	 * get_channels(); look at ethtool.c in ethtool repository (the user
345962306a36Sopenharmony_ci	 * space part), particularly, do_schannels() routine
346062306a36Sopenharmony_ci	 */
346162306a36Sopenharmony_ci	if (ch->rx_count == vsi->num_rxq - curr_combined)
346262306a36Sopenharmony_ci		ch->rx_count = 0;
346362306a36Sopenharmony_ci	if (ch->tx_count == vsi->num_txq - curr_combined)
346462306a36Sopenharmony_ci		ch->tx_count = 0;
346562306a36Sopenharmony_ci	if (ch->combined_count == curr_combined)
346662306a36Sopenharmony_ci		ch->combined_count = 0;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	if (!(ch->combined_count || (ch->rx_count && ch->tx_count))) {
346962306a36Sopenharmony_ci		netdev_err(dev, "Please specify at least 1 Rx and 1 Tx channel\n");
347062306a36Sopenharmony_ci		return -EINVAL;
347162306a36Sopenharmony_ci	}
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	new_rx = ch->combined_count + ch->rx_count;
347462306a36Sopenharmony_ci	new_tx = ch->combined_count + ch->tx_count;
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	if (new_rx < vsi->tc_cfg.numtc) {
347762306a36Sopenharmony_ci		netdev_err(dev, "Cannot set less Rx channels, than Traffic Classes you have (%u)\n",
347862306a36Sopenharmony_ci			   vsi->tc_cfg.numtc);
347962306a36Sopenharmony_ci		return -EINVAL;
348062306a36Sopenharmony_ci	}
348162306a36Sopenharmony_ci	if (new_tx < vsi->tc_cfg.numtc) {
348262306a36Sopenharmony_ci		netdev_err(dev, "Cannot set less Tx channels, than Traffic Classes you have (%u)\n",
348362306a36Sopenharmony_ci			   vsi->tc_cfg.numtc);
348462306a36Sopenharmony_ci		return -EINVAL;
348562306a36Sopenharmony_ci	}
348662306a36Sopenharmony_ci	if (new_rx > ice_get_max_rxq(pf)) {
348762306a36Sopenharmony_ci		netdev_err(dev, "Maximum allowed Rx channels is %d\n",
348862306a36Sopenharmony_ci			   ice_get_max_rxq(pf));
348962306a36Sopenharmony_ci		return -EINVAL;
349062306a36Sopenharmony_ci	}
349162306a36Sopenharmony_ci	if (new_tx > ice_get_max_txq(pf)) {
349262306a36Sopenharmony_ci		netdev_err(dev, "Maximum allowed Tx channels is %d\n",
349362306a36Sopenharmony_ci			   ice_get_max_txq(pf));
349462306a36Sopenharmony_ci		return -EINVAL;
349562306a36Sopenharmony_ci	}
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	if (pf->adev) {
349862306a36Sopenharmony_ci		mutex_lock(&pf->adev_mutex);
349962306a36Sopenharmony_ci		device_lock(&pf->adev->dev);
350062306a36Sopenharmony_ci		locked = true;
350162306a36Sopenharmony_ci		if (pf->adev->dev.driver) {
350262306a36Sopenharmony_ci			netdev_err(dev, "Cannot change channels when RDMA is active\n");
350362306a36Sopenharmony_ci			ret = -EBUSY;
350462306a36Sopenharmony_ci			goto adev_unlock;
350562306a36Sopenharmony_ci		}
350662306a36Sopenharmony_ci	}
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_ci	ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked);
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci	if (!netif_is_rxfh_configured(dev)) {
351162306a36Sopenharmony_ci		ret = ice_vsi_set_dflt_rss_lut(vsi, new_rx);
351262306a36Sopenharmony_ci		goto adev_unlock;
351362306a36Sopenharmony_ci	}
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	/* Update rss_size due to change in Rx queues */
351662306a36Sopenharmony_ci	vsi->rss_size = ice_get_valid_rss_size(&pf->hw, new_rx);
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ciadev_unlock:
351962306a36Sopenharmony_ci	if (locked) {
352062306a36Sopenharmony_ci		device_unlock(&pf->adev->dev);
352162306a36Sopenharmony_ci		mutex_unlock(&pf->adev_mutex);
352262306a36Sopenharmony_ci	}
352362306a36Sopenharmony_ci	return ret;
352462306a36Sopenharmony_ci}
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci/**
352762306a36Sopenharmony_ci * ice_get_wol - get current Wake on LAN configuration
352862306a36Sopenharmony_ci * @netdev: network interface device structure
352962306a36Sopenharmony_ci * @wol: Ethtool structure to retrieve WoL settings
353062306a36Sopenharmony_ci */
353162306a36Sopenharmony_cistatic void ice_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
353262306a36Sopenharmony_ci{
353362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
353462306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	if (np->vsi->type != ICE_VSI_PF)
353762306a36Sopenharmony_ci		netdev_warn(netdev, "Wake on LAN is not supported on this interface!\n");
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_ci	/* Get WoL settings based on the HW capability */
354062306a36Sopenharmony_ci	if (ice_is_wol_supported(&pf->hw)) {
354162306a36Sopenharmony_ci		wol->supported = WAKE_MAGIC;
354262306a36Sopenharmony_ci		wol->wolopts = pf->wol_ena ? WAKE_MAGIC : 0;
354362306a36Sopenharmony_ci	} else {
354462306a36Sopenharmony_ci		wol->supported = 0;
354562306a36Sopenharmony_ci		wol->wolopts = 0;
354662306a36Sopenharmony_ci	}
354762306a36Sopenharmony_ci}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci/**
355062306a36Sopenharmony_ci * ice_set_wol - set Wake on LAN on supported device
355162306a36Sopenharmony_ci * @netdev: network interface device structure
355262306a36Sopenharmony_ci * @wol: Ethtool structure to set WoL
355362306a36Sopenharmony_ci */
355462306a36Sopenharmony_cistatic int ice_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
355562306a36Sopenharmony_ci{
355662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
355762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
355862306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF || !ice_is_wol_supported(&pf->hw))
356162306a36Sopenharmony_ci		return -EOPNOTSUPP;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	/* only magic packet is supported */
356462306a36Sopenharmony_ci	if (wol->wolopts && wol->wolopts != WAKE_MAGIC)
356562306a36Sopenharmony_ci		return -EOPNOTSUPP;
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	/* Set WoL only if there is a new value */
356862306a36Sopenharmony_ci	if (pf->wol_ena != !!wol->wolopts) {
356962306a36Sopenharmony_ci		pf->wol_ena = !!wol->wolopts;
357062306a36Sopenharmony_ci		device_set_wakeup_enable(ice_pf_to_dev(pf), pf->wol_ena);
357162306a36Sopenharmony_ci		netdev_dbg(netdev, "WoL magic packet %sabled\n",
357262306a36Sopenharmony_ci			   pf->wol_ena ? "en" : "dis");
357362306a36Sopenharmony_ci	}
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	return 0;
357662306a36Sopenharmony_ci}
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci/**
357962306a36Sopenharmony_ci * ice_get_rc_coalesce - get ITR values for specific ring container
358062306a36Sopenharmony_ci * @ec: ethtool structure to fill with driver's coalesce settings
358162306a36Sopenharmony_ci * @rc: ring container that the ITR values will come from
358262306a36Sopenharmony_ci *
358362306a36Sopenharmony_ci * Query the device for ice_ring_container specific ITR values. This is
358462306a36Sopenharmony_ci * done per ice_ring_container because each q_vector can have 1 or more rings
358562306a36Sopenharmony_ci * and all of said ring(s) will have the same ITR values.
358662306a36Sopenharmony_ci *
358762306a36Sopenharmony_ci * Returns 0 on success, negative otherwise.
358862306a36Sopenharmony_ci */
358962306a36Sopenharmony_cistatic int
359062306a36Sopenharmony_ciice_get_rc_coalesce(struct ethtool_coalesce *ec, struct ice_ring_container *rc)
359162306a36Sopenharmony_ci{
359262306a36Sopenharmony_ci	if (!rc->rx_ring)
359362306a36Sopenharmony_ci		return -EINVAL;
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	switch (rc->type) {
359662306a36Sopenharmony_ci	case ICE_RX_CONTAINER:
359762306a36Sopenharmony_ci		ec->use_adaptive_rx_coalesce = ITR_IS_DYNAMIC(rc);
359862306a36Sopenharmony_ci		ec->rx_coalesce_usecs = rc->itr_setting;
359962306a36Sopenharmony_ci		ec->rx_coalesce_usecs_high = rc->rx_ring->q_vector->intrl;
360062306a36Sopenharmony_ci		break;
360162306a36Sopenharmony_ci	case ICE_TX_CONTAINER:
360262306a36Sopenharmony_ci		ec->use_adaptive_tx_coalesce = ITR_IS_DYNAMIC(rc);
360362306a36Sopenharmony_ci		ec->tx_coalesce_usecs = rc->itr_setting;
360462306a36Sopenharmony_ci		break;
360562306a36Sopenharmony_ci	default:
360662306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(rc->rx_ring->vsi->back), "Invalid c_type %d\n", rc->type);
360762306a36Sopenharmony_ci		return -EINVAL;
360862306a36Sopenharmony_ci	}
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	return 0;
361162306a36Sopenharmony_ci}
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci/**
361462306a36Sopenharmony_ci * ice_get_q_coalesce - get a queue's ITR/INTRL (coalesce) settings
361562306a36Sopenharmony_ci * @vsi: VSI associated to the queue for getting ITR/INTRL (coalesce) settings
361662306a36Sopenharmony_ci * @ec: coalesce settings to program the device with
361762306a36Sopenharmony_ci * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index
361862306a36Sopenharmony_ci *
361962306a36Sopenharmony_ci * Return 0 on success, and negative under the following conditions:
362062306a36Sopenharmony_ci * 1. Getting Tx or Rx ITR/INTRL (coalesce) settings failed.
362162306a36Sopenharmony_ci * 2. The q_num passed in is not a valid number/index for Tx and Rx rings.
362262306a36Sopenharmony_ci */
362362306a36Sopenharmony_cistatic int
362462306a36Sopenharmony_ciice_get_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num)
362562306a36Sopenharmony_ci{
362662306a36Sopenharmony_ci	if (q_num < vsi->num_rxq && q_num < vsi->num_txq) {
362762306a36Sopenharmony_ci		if (ice_get_rc_coalesce(ec,
362862306a36Sopenharmony_ci					&vsi->rx_rings[q_num]->q_vector->rx))
362962306a36Sopenharmony_ci			return -EINVAL;
363062306a36Sopenharmony_ci		if (ice_get_rc_coalesce(ec,
363162306a36Sopenharmony_ci					&vsi->tx_rings[q_num]->q_vector->tx))
363262306a36Sopenharmony_ci			return -EINVAL;
363362306a36Sopenharmony_ci	} else if (q_num < vsi->num_rxq) {
363462306a36Sopenharmony_ci		if (ice_get_rc_coalesce(ec,
363562306a36Sopenharmony_ci					&vsi->rx_rings[q_num]->q_vector->rx))
363662306a36Sopenharmony_ci			return -EINVAL;
363762306a36Sopenharmony_ci	} else if (q_num < vsi->num_txq) {
363862306a36Sopenharmony_ci		if (ice_get_rc_coalesce(ec,
363962306a36Sopenharmony_ci					&vsi->tx_rings[q_num]->q_vector->tx))
364062306a36Sopenharmony_ci			return -EINVAL;
364162306a36Sopenharmony_ci	} else {
364262306a36Sopenharmony_ci		return -EINVAL;
364362306a36Sopenharmony_ci	}
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci	return 0;
364662306a36Sopenharmony_ci}
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_ci/**
364962306a36Sopenharmony_ci * __ice_get_coalesce - get ITR/INTRL values for the device
365062306a36Sopenharmony_ci * @netdev: pointer to the netdev associated with this query
365162306a36Sopenharmony_ci * @ec: ethtool structure to fill with driver's coalesce settings
365262306a36Sopenharmony_ci * @q_num: queue number to get the coalesce settings for
365362306a36Sopenharmony_ci *
365462306a36Sopenharmony_ci * If the caller passes in a negative q_num then we return coalesce settings
365562306a36Sopenharmony_ci * based on queue number 0, else use the actual q_num passed in.
365662306a36Sopenharmony_ci */
365762306a36Sopenharmony_cistatic int
365862306a36Sopenharmony_ci__ice_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec,
365962306a36Sopenharmony_ci		   int q_num)
366062306a36Sopenharmony_ci{
366162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
366262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci	if (q_num < 0)
366562306a36Sopenharmony_ci		q_num = 0;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	if (ice_get_q_coalesce(vsi, ec, q_num))
366862306a36Sopenharmony_ci		return -EINVAL;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	return 0;
367162306a36Sopenharmony_ci}
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_cistatic int ice_get_coalesce(struct net_device *netdev,
367462306a36Sopenharmony_ci			    struct ethtool_coalesce *ec,
367562306a36Sopenharmony_ci			    struct kernel_ethtool_coalesce *kernel_coal,
367662306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
367762306a36Sopenharmony_ci{
367862306a36Sopenharmony_ci	return __ice_get_coalesce(netdev, ec, -1);
367962306a36Sopenharmony_ci}
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_cistatic int
368262306a36Sopenharmony_ciice_get_per_q_coalesce(struct net_device *netdev, u32 q_num,
368362306a36Sopenharmony_ci		       struct ethtool_coalesce *ec)
368462306a36Sopenharmony_ci{
368562306a36Sopenharmony_ci	return __ice_get_coalesce(netdev, ec, q_num);
368662306a36Sopenharmony_ci}
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci/**
368962306a36Sopenharmony_ci * ice_set_rc_coalesce - set ITR values for specific ring container
369062306a36Sopenharmony_ci * @ec: ethtool structure from user to update ITR settings
369162306a36Sopenharmony_ci * @rc: ring container that the ITR values will come from
369262306a36Sopenharmony_ci * @vsi: VSI associated to the ring container
369362306a36Sopenharmony_ci *
369462306a36Sopenharmony_ci * Set specific ITR values. This is done per ice_ring_container because each
369562306a36Sopenharmony_ci * q_vector can have 1 or more rings and all of said ring(s) will have the same
369662306a36Sopenharmony_ci * ITR values.
369762306a36Sopenharmony_ci *
369862306a36Sopenharmony_ci * Returns 0 on success, negative otherwise.
369962306a36Sopenharmony_ci */
370062306a36Sopenharmony_cistatic int
370162306a36Sopenharmony_ciice_set_rc_coalesce(struct ethtool_coalesce *ec,
370262306a36Sopenharmony_ci		    struct ice_ring_container *rc, struct ice_vsi *vsi)
370362306a36Sopenharmony_ci{
370462306a36Sopenharmony_ci	const char *c_type_str = (rc->type == ICE_RX_CONTAINER) ? "rx" : "tx";
370562306a36Sopenharmony_ci	u32 use_adaptive_coalesce, coalesce_usecs;
370662306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
370762306a36Sopenharmony_ci	u16 itr_setting;
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	if (!rc->rx_ring)
371062306a36Sopenharmony_ci		return -EINVAL;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	switch (rc->type) {
371362306a36Sopenharmony_ci	case ICE_RX_CONTAINER:
371462306a36Sopenharmony_ci	{
371562306a36Sopenharmony_ci		struct ice_q_vector *q_vector = rc->rx_ring->q_vector;
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci		if (ec->rx_coalesce_usecs_high > ICE_MAX_INTRL ||
371862306a36Sopenharmony_ci		    (ec->rx_coalesce_usecs_high &&
371962306a36Sopenharmony_ci		     ec->rx_coalesce_usecs_high < pf->hw.intrl_gran)) {
372062306a36Sopenharmony_ci			netdev_info(vsi->netdev, "Invalid value, %s-usecs-high valid values are 0 (disabled), %d-%d\n",
372162306a36Sopenharmony_ci				    c_type_str, pf->hw.intrl_gran,
372262306a36Sopenharmony_ci				    ICE_MAX_INTRL);
372362306a36Sopenharmony_ci			return -EINVAL;
372462306a36Sopenharmony_ci		}
372562306a36Sopenharmony_ci		if (ec->rx_coalesce_usecs_high != q_vector->intrl &&
372662306a36Sopenharmony_ci		    (ec->use_adaptive_rx_coalesce || ec->use_adaptive_tx_coalesce)) {
372762306a36Sopenharmony_ci			netdev_info(vsi->netdev, "Invalid value, %s-usecs-high cannot be changed if adaptive-tx or adaptive-rx is enabled\n",
372862306a36Sopenharmony_ci				    c_type_str);
372962306a36Sopenharmony_ci			return -EINVAL;
373062306a36Sopenharmony_ci		}
373162306a36Sopenharmony_ci		if (ec->rx_coalesce_usecs_high != q_vector->intrl)
373262306a36Sopenharmony_ci			q_vector->intrl = ec->rx_coalesce_usecs_high;
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci		use_adaptive_coalesce = ec->use_adaptive_rx_coalesce;
373562306a36Sopenharmony_ci		coalesce_usecs = ec->rx_coalesce_usecs;
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci		break;
373862306a36Sopenharmony_ci	}
373962306a36Sopenharmony_ci	case ICE_TX_CONTAINER:
374062306a36Sopenharmony_ci		use_adaptive_coalesce = ec->use_adaptive_tx_coalesce;
374162306a36Sopenharmony_ci		coalesce_usecs = ec->tx_coalesce_usecs;
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci		break;
374462306a36Sopenharmony_ci	default:
374562306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n",
374662306a36Sopenharmony_ci			rc->type);
374762306a36Sopenharmony_ci		return -EINVAL;
374862306a36Sopenharmony_ci	}
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci	itr_setting = rc->itr_setting;
375162306a36Sopenharmony_ci	if (coalesce_usecs != itr_setting && use_adaptive_coalesce) {
375262306a36Sopenharmony_ci		netdev_info(vsi->netdev, "%s interrupt throttling cannot be changed if adaptive-%s is enabled\n",
375362306a36Sopenharmony_ci			    c_type_str, c_type_str);
375462306a36Sopenharmony_ci		return -EINVAL;
375562306a36Sopenharmony_ci	}
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_ci	if (coalesce_usecs > ICE_ITR_MAX) {
375862306a36Sopenharmony_ci		netdev_info(vsi->netdev, "Invalid value, %s-usecs range is 0-%d\n",
375962306a36Sopenharmony_ci			    c_type_str, ICE_ITR_MAX);
376062306a36Sopenharmony_ci		return -EINVAL;
376162306a36Sopenharmony_ci	}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	if (use_adaptive_coalesce) {
376462306a36Sopenharmony_ci		rc->itr_mode = ITR_DYNAMIC;
376562306a36Sopenharmony_ci	} else {
376662306a36Sopenharmony_ci		rc->itr_mode = ITR_STATIC;
376762306a36Sopenharmony_ci		/* store user facing value how it was set */
376862306a36Sopenharmony_ci		rc->itr_setting = coalesce_usecs;
376962306a36Sopenharmony_ci		/* write the change to the register */
377062306a36Sopenharmony_ci		ice_write_itr(rc, coalesce_usecs);
377162306a36Sopenharmony_ci		/* force writes to take effect immediately, the flush shouldn't
377262306a36Sopenharmony_ci		 * be done in the functions above because the intent is for
377362306a36Sopenharmony_ci		 * them to do lazy writes.
377462306a36Sopenharmony_ci		 */
377562306a36Sopenharmony_ci		ice_flush(&pf->hw);
377662306a36Sopenharmony_ci	}
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci	return 0;
377962306a36Sopenharmony_ci}
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci/**
378262306a36Sopenharmony_ci * ice_set_q_coalesce - set a queue's ITR/INTRL (coalesce) settings
378362306a36Sopenharmony_ci * @vsi: VSI associated to the queue that need updating
378462306a36Sopenharmony_ci * @ec: coalesce settings to program the device with
378562306a36Sopenharmony_ci * @q_num: update ITR/INTRL (coalesce) settings for this queue number/index
378662306a36Sopenharmony_ci *
378762306a36Sopenharmony_ci * Return 0 on success, and negative under the following conditions:
378862306a36Sopenharmony_ci * 1. Setting Tx or Rx ITR/INTRL (coalesce) settings failed.
378962306a36Sopenharmony_ci * 2. The q_num passed in is not a valid number/index for Tx and Rx rings.
379062306a36Sopenharmony_ci */
379162306a36Sopenharmony_cistatic int
379262306a36Sopenharmony_ciice_set_q_coalesce(struct ice_vsi *vsi, struct ethtool_coalesce *ec, int q_num)
379362306a36Sopenharmony_ci{
379462306a36Sopenharmony_ci	if (q_num < vsi->num_rxq && q_num < vsi->num_txq) {
379562306a36Sopenharmony_ci		if (ice_set_rc_coalesce(ec,
379662306a36Sopenharmony_ci					&vsi->rx_rings[q_num]->q_vector->rx,
379762306a36Sopenharmony_ci					vsi))
379862306a36Sopenharmony_ci			return -EINVAL;
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci		if (ice_set_rc_coalesce(ec,
380162306a36Sopenharmony_ci					&vsi->tx_rings[q_num]->q_vector->tx,
380262306a36Sopenharmony_ci					vsi))
380362306a36Sopenharmony_ci			return -EINVAL;
380462306a36Sopenharmony_ci	} else if (q_num < vsi->num_rxq) {
380562306a36Sopenharmony_ci		if (ice_set_rc_coalesce(ec,
380662306a36Sopenharmony_ci					&vsi->rx_rings[q_num]->q_vector->rx,
380762306a36Sopenharmony_ci					vsi))
380862306a36Sopenharmony_ci			return -EINVAL;
380962306a36Sopenharmony_ci	} else if (q_num < vsi->num_txq) {
381062306a36Sopenharmony_ci		if (ice_set_rc_coalesce(ec,
381162306a36Sopenharmony_ci					&vsi->tx_rings[q_num]->q_vector->tx,
381262306a36Sopenharmony_ci					vsi))
381362306a36Sopenharmony_ci			return -EINVAL;
381462306a36Sopenharmony_ci	} else {
381562306a36Sopenharmony_ci		return -EINVAL;
381662306a36Sopenharmony_ci	}
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	return 0;
381962306a36Sopenharmony_ci}
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_ci/**
382262306a36Sopenharmony_ci * ice_print_if_odd_usecs - print message if user tries to set odd [tx|rx]-usecs
382362306a36Sopenharmony_ci * @netdev: netdev used for print
382462306a36Sopenharmony_ci * @itr_setting: previous user setting
382562306a36Sopenharmony_ci * @use_adaptive_coalesce: if adaptive coalesce is enabled or being enabled
382662306a36Sopenharmony_ci * @coalesce_usecs: requested value of [tx|rx]-usecs
382762306a36Sopenharmony_ci * @c_type_str: either "rx" or "tx" to match user set field of [tx|rx]-usecs
382862306a36Sopenharmony_ci */
382962306a36Sopenharmony_cistatic void
383062306a36Sopenharmony_ciice_print_if_odd_usecs(struct net_device *netdev, u16 itr_setting,
383162306a36Sopenharmony_ci		       u32 use_adaptive_coalesce, u32 coalesce_usecs,
383262306a36Sopenharmony_ci		       const char *c_type_str)
383362306a36Sopenharmony_ci{
383462306a36Sopenharmony_ci	if (use_adaptive_coalesce)
383562306a36Sopenharmony_ci		return;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	if (itr_setting != coalesce_usecs && (coalesce_usecs % 2))
383862306a36Sopenharmony_ci		netdev_info(netdev, "User set %s-usecs to %d, device only supports even values. Rounding down and attempting to set %s-usecs to %d\n",
383962306a36Sopenharmony_ci			    c_type_str, coalesce_usecs, c_type_str,
384062306a36Sopenharmony_ci			    ITR_REG_ALIGN(coalesce_usecs));
384162306a36Sopenharmony_ci}
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_ci/**
384462306a36Sopenharmony_ci * __ice_set_coalesce - set ITR/INTRL values for the device
384562306a36Sopenharmony_ci * @netdev: pointer to the netdev associated with this query
384662306a36Sopenharmony_ci * @ec: ethtool structure to fill with driver's coalesce settings
384762306a36Sopenharmony_ci * @q_num: queue number to get the coalesce settings for
384862306a36Sopenharmony_ci *
384962306a36Sopenharmony_ci * If the caller passes in a negative q_num then we set the coalesce settings
385062306a36Sopenharmony_ci * for all Tx/Rx queues, else use the actual q_num passed in.
385162306a36Sopenharmony_ci */
385262306a36Sopenharmony_cistatic int
385362306a36Sopenharmony_ci__ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec,
385462306a36Sopenharmony_ci		   int q_num)
385562306a36Sopenharmony_ci{
385662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
385762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	if (q_num < 0) {
386062306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[0];
386162306a36Sopenharmony_ci		int v_idx;
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci		if (q_vector) {
386462306a36Sopenharmony_ci			ice_print_if_odd_usecs(netdev, q_vector->rx.itr_setting,
386562306a36Sopenharmony_ci					       ec->use_adaptive_rx_coalesce,
386662306a36Sopenharmony_ci					       ec->rx_coalesce_usecs, "rx");
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci			ice_print_if_odd_usecs(netdev, q_vector->tx.itr_setting,
386962306a36Sopenharmony_ci					       ec->use_adaptive_tx_coalesce,
387062306a36Sopenharmony_ci					       ec->tx_coalesce_usecs, "tx");
387162306a36Sopenharmony_ci		}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci		ice_for_each_q_vector(vsi, v_idx) {
387462306a36Sopenharmony_ci			/* In some cases if DCB is configured the num_[rx|tx]q
387562306a36Sopenharmony_ci			 * can be less than vsi->num_q_vectors. This check
387662306a36Sopenharmony_ci			 * accounts for that so we don't report a false failure
387762306a36Sopenharmony_ci			 */
387862306a36Sopenharmony_ci			if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq)
387962306a36Sopenharmony_ci				goto set_complete;
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci			if (ice_set_q_coalesce(vsi, ec, v_idx))
388262306a36Sopenharmony_ci				return -EINVAL;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci			ice_set_q_vector_intrl(vsi->q_vectors[v_idx]);
388562306a36Sopenharmony_ci		}
388662306a36Sopenharmony_ci		goto set_complete;
388762306a36Sopenharmony_ci	}
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	if (ice_set_q_coalesce(vsi, ec, q_num))
389062306a36Sopenharmony_ci		return -EINVAL;
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	ice_set_q_vector_intrl(vsi->q_vectors[q_num]);
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_ciset_complete:
389562306a36Sopenharmony_ci	return 0;
389662306a36Sopenharmony_ci}
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_cistatic int ice_set_coalesce(struct net_device *netdev,
389962306a36Sopenharmony_ci			    struct ethtool_coalesce *ec,
390062306a36Sopenharmony_ci			    struct kernel_ethtool_coalesce *kernel_coal,
390162306a36Sopenharmony_ci			    struct netlink_ext_ack *extack)
390262306a36Sopenharmony_ci{
390362306a36Sopenharmony_ci	return __ice_set_coalesce(netdev, ec, -1);
390462306a36Sopenharmony_ci}
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_cistatic int
390762306a36Sopenharmony_ciice_set_per_q_coalesce(struct net_device *netdev, u32 q_num,
390862306a36Sopenharmony_ci		       struct ethtool_coalesce *ec)
390962306a36Sopenharmony_ci{
391062306a36Sopenharmony_ci	return __ice_set_coalesce(netdev, ec, q_num);
391162306a36Sopenharmony_ci}
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_cistatic void
391462306a36Sopenharmony_ciice_repr_get_drvinfo(struct net_device *netdev,
391562306a36Sopenharmony_ci		     struct ethtool_drvinfo *drvinfo)
391662306a36Sopenharmony_ci{
391762306a36Sopenharmony_ci	struct ice_repr *repr = ice_netdev_to_repr(netdev);
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	if (ice_check_vf_ready_for_cfg(repr->vf))
392062306a36Sopenharmony_ci		return;
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	__ice_get_drvinfo(netdev, drvinfo, repr->src_vsi);
392362306a36Sopenharmony_ci}
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_cistatic void
392662306a36Sopenharmony_ciice_repr_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
392762306a36Sopenharmony_ci{
392862306a36Sopenharmony_ci	struct ice_repr *repr = ice_netdev_to_repr(netdev);
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_ci	/* for port representors only ETH_SS_STATS is supported */
393162306a36Sopenharmony_ci	if (ice_check_vf_ready_for_cfg(repr->vf) ||
393262306a36Sopenharmony_ci	    stringset != ETH_SS_STATS)
393362306a36Sopenharmony_ci		return;
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci	__ice_get_strings(netdev, stringset, data, repr->src_vsi);
393662306a36Sopenharmony_ci}
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_cistatic void
393962306a36Sopenharmony_ciice_repr_get_ethtool_stats(struct net_device *netdev,
394062306a36Sopenharmony_ci			   struct ethtool_stats __always_unused *stats,
394162306a36Sopenharmony_ci			   u64 *data)
394262306a36Sopenharmony_ci{
394362306a36Sopenharmony_ci	struct ice_repr *repr = ice_netdev_to_repr(netdev);
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci	if (ice_check_vf_ready_for_cfg(repr->vf))
394662306a36Sopenharmony_ci		return;
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ci	__ice_get_ethtool_stats(netdev, stats, data, repr->src_vsi);
394962306a36Sopenharmony_ci}
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_cistatic int ice_repr_get_sset_count(struct net_device *netdev, int sset)
395262306a36Sopenharmony_ci{
395362306a36Sopenharmony_ci	switch (sset) {
395462306a36Sopenharmony_ci	case ETH_SS_STATS:
395562306a36Sopenharmony_ci		return ICE_VSI_STATS_LEN;
395662306a36Sopenharmony_ci	default:
395762306a36Sopenharmony_ci		return -EOPNOTSUPP;
395862306a36Sopenharmony_ci	}
395962306a36Sopenharmony_ci}
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci#define ICE_I2C_EEPROM_DEV_ADDR		0xA0
396262306a36Sopenharmony_ci#define ICE_I2C_EEPROM_DEV_ADDR2	0xA2
396362306a36Sopenharmony_ci#define ICE_MODULE_TYPE_SFP		0x03
396462306a36Sopenharmony_ci#define ICE_MODULE_TYPE_QSFP_PLUS	0x0D
396562306a36Sopenharmony_ci#define ICE_MODULE_TYPE_QSFP28		0x11
396662306a36Sopenharmony_ci#define ICE_MODULE_SFF_ADDR_MODE	0x04
396762306a36Sopenharmony_ci#define ICE_MODULE_SFF_DIAG_CAPAB	0x40
396862306a36Sopenharmony_ci#define ICE_MODULE_REVISION_ADDR	0x01
396962306a36Sopenharmony_ci#define ICE_MODULE_SFF_8472_COMP	0x5E
397062306a36Sopenharmony_ci#define ICE_MODULE_SFF_8472_SWAP	0x5C
397162306a36Sopenharmony_ci#define ICE_MODULE_QSFP_MAX_LEN		640
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci/**
397462306a36Sopenharmony_ci * ice_get_module_info - get SFF module type and revision information
397562306a36Sopenharmony_ci * @netdev: network interface device structure
397662306a36Sopenharmony_ci * @modinfo: module EEPROM size and layout information structure
397762306a36Sopenharmony_ci */
397862306a36Sopenharmony_cistatic int
397962306a36Sopenharmony_ciice_get_module_info(struct net_device *netdev,
398062306a36Sopenharmony_ci		    struct ethtool_modinfo *modinfo)
398162306a36Sopenharmony_ci{
398262306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
398362306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
398462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
398562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
398662306a36Sopenharmony_ci	u8 sff8472_comp = 0;
398762306a36Sopenharmony_ci	u8 sff8472_swap = 0;
398862306a36Sopenharmony_ci	u8 sff8636_rev = 0;
398962306a36Sopenharmony_ci	u8 value = 0;
399062306a36Sopenharmony_ci	int status;
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 0x00, 0x00,
399362306a36Sopenharmony_ci				   0, &value, 1, 0, NULL);
399462306a36Sopenharmony_ci	if (status)
399562306a36Sopenharmony_ci		return status;
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci	switch (value) {
399862306a36Sopenharmony_ci	case ICE_MODULE_TYPE_SFP:
399962306a36Sopenharmony_ci		status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR,
400062306a36Sopenharmony_ci					   ICE_MODULE_SFF_8472_COMP, 0x00, 0,
400162306a36Sopenharmony_ci					   &sff8472_comp, 1, 0, NULL);
400262306a36Sopenharmony_ci		if (status)
400362306a36Sopenharmony_ci			return status;
400462306a36Sopenharmony_ci		status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR,
400562306a36Sopenharmony_ci					   ICE_MODULE_SFF_8472_SWAP, 0x00, 0,
400662306a36Sopenharmony_ci					   &sff8472_swap, 1, 0, NULL);
400762306a36Sopenharmony_ci		if (status)
400862306a36Sopenharmony_ci			return status;
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci		if (sff8472_swap & ICE_MODULE_SFF_ADDR_MODE) {
401162306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8079;
401262306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
401362306a36Sopenharmony_ci		} else if (sff8472_comp &&
401462306a36Sopenharmony_ci			   (sff8472_swap & ICE_MODULE_SFF_DIAG_CAPAB)) {
401562306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8472;
401662306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
401762306a36Sopenharmony_ci		} else {
401862306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8079;
401962306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
402062306a36Sopenharmony_ci		}
402162306a36Sopenharmony_ci		break;
402262306a36Sopenharmony_ci	case ICE_MODULE_TYPE_QSFP_PLUS:
402362306a36Sopenharmony_ci	case ICE_MODULE_TYPE_QSFP28:
402462306a36Sopenharmony_ci		status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR,
402562306a36Sopenharmony_ci					   ICE_MODULE_REVISION_ADDR, 0x00, 0,
402662306a36Sopenharmony_ci					   &sff8636_rev, 1, 0, NULL);
402762306a36Sopenharmony_ci		if (status)
402862306a36Sopenharmony_ci			return status;
402962306a36Sopenharmony_ci		/* Check revision compliance */
403062306a36Sopenharmony_ci		if (sff8636_rev > 0x02) {
403162306a36Sopenharmony_ci			/* Module is SFF-8636 compliant */
403262306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8636;
403362306a36Sopenharmony_ci			modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN;
403462306a36Sopenharmony_ci		} else {
403562306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8436;
403662306a36Sopenharmony_ci			modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN;
403762306a36Sopenharmony_ci		}
403862306a36Sopenharmony_ci		break;
403962306a36Sopenharmony_ci	default:
404062306a36Sopenharmony_ci		netdev_warn(netdev, "SFF Module Type not recognized.\n");
404162306a36Sopenharmony_ci		return -EINVAL;
404262306a36Sopenharmony_ci	}
404362306a36Sopenharmony_ci	return 0;
404462306a36Sopenharmony_ci}
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci/**
404762306a36Sopenharmony_ci * ice_get_module_eeprom - fill buffer with SFF EEPROM contents
404862306a36Sopenharmony_ci * @netdev: network interface device structure
404962306a36Sopenharmony_ci * @ee: EEPROM dump request structure
405062306a36Sopenharmony_ci * @data: buffer to be filled with EEPROM contents
405162306a36Sopenharmony_ci */
405262306a36Sopenharmony_cistatic int
405362306a36Sopenharmony_ciice_get_module_eeprom(struct net_device *netdev,
405462306a36Sopenharmony_ci		      struct ethtool_eeprom *ee, u8 *data)
405562306a36Sopenharmony_ci{
405662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
405762306a36Sopenharmony_ci#define SFF_READ_BLOCK_SIZE 8
405862306a36Sopenharmony_ci	u8 value[SFF_READ_BLOCK_SIZE] = { 0 };
405962306a36Sopenharmony_ci	u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
406062306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
406162306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
406262306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
406362306a36Sopenharmony_ci	bool is_sfp = false;
406462306a36Sopenharmony_ci	unsigned int i, j;
406562306a36Sopenharmony_ci	u16 offset = 0;
406662306a36Sopenharmony_ci	u8 page = 0;
406762306a36Sopenharmony_ci	int status;
406862306a36Sopenharmony_ci
406962306a36Sopenharmony_ci	if (!ee || !ee->len || !data)
407062306a36Sopenharmony_ci		return -EINVAL;
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, value, 1, 0,
407362306a36Sopenharmony_ci				   NULL);
407462306a36Sopenharmony_ci	if (status)
407562306a36Sopenharmony_ci		return status;
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci	if (value[0] == ICE_MODULE_TYPE_SFP)
407862306a36Sopenharmony_ci		is_sfp = true;
407962306a36Sopenharmony_ci
408062306a36Sopenharmony_ci	memset(data, 0, ee->len);
408162306a36Sopenharmony_ci	for (i = 0; i < ee->len; i += SFF_READ_BLOCK_SIZE) {
408262306a36Sopenharmony_ci		offset = i + ee->offset;
408362306a36Sopenharmony_ci		page = 0;
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci		/* Check if we need to access the other memory page */
408662306a36Sopenharmony_ci		if (is_sfp) {
408762306a36Sopenharmony_ci			if (offset >= ETH_MODULE_SFF_8079_LEN) {
408862306a36Sopenharmony_ci				offset -= ETH_MODULE_SFF_8079_LEN;
408962306a36Sopenharmony_ci				addr = ICE_I2C_EEPROM_DEV_ADDR2;
409062306a36Sopenharmony_ci			}
409162306a36Sopenharmony_ci		} else {
409262306a36Sopenharmony_ci			while (offset >= ETH_MODULE_SFF_8436_LEN) {
409362306a36Sopenharmony_ci				/* Compute memory page number and offset. */
409462306a36Sopenharmony_ci				offset -= ETH_MODULE_SFF_8436_LEN / 2;
409562306a36Sopenharmony_ci				page++;
409662306a36Sopenharmony_ci			}
409762306a36Sopenharmony_ci		}
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci		/* Bit 2 of EEPROM address 0x02 declares upper
410062306a36Sopenharmony_ci		 * pages are disabled on QSFP modules.
410162306a36Sopenharmony_ci		 * SFP modules only ever use page 0.
410262306a36Sopenharmony_ci		 */
410362306a36Sopenharmony_ci		if (page == 0 || !(data[0x2] & 0x4)) {
410462306a36Sopenharmony_ci			u32 copy_len;
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci			/* If i2c bus is busy due to slow page change or
410762306a36Sopenharmony_ci			 * link management access, call can fail. This is normal.
410862306a36Sopenharmony_ci			 * So we retry this a few times.
410962306a36Sopenharmony_ci			 */
411062306a36Sopenharmony_ci			for (j = 0; j < 4; j++) {
411162306a36Sopenharmony_ci				status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
411262306a36Sopenharmony_ci							   !is_sfp, value,
411362306a36Sopenharmony_ci							   SFF_READ_BLOCK_SIZE,
411462306a36Sopenharmony_ci							   0, NULL);
411562306a36Sopenharmony_ci				netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
411662306a36Sopenharmony_ci					   addr, offset, page, is_sfp,
411762306a36Sopenharmony_ci					   value[0], value[1], value[2], value[3],
411862306a36Sopenharmony_ci					   value[4], value[5], value[6], value[7],
411962306a36Sopenharmony_ci					   status);
412062306a36Sopenharmony_ci				if (status) {
412162306a36Sopenharmony_ci					usleep_range(1500, 2500);
412262306a36Sopenharmony_ci					memset(value, 0, SFF_READ_BLOCK_SIZE);
412362306a36Sopenharmony_ci					continue;
412462306a36Sopenharmony_ci				}
412562306a36Sopenharmony_ci				break;
412662306a36Sopenharmony_ci			}
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci			/* Make sure we have enough room for the new block */
412962306a36Sopenharmony_ci			copy_len = min_t(u32, SFF_READ_BLOCK_SIZE, ee->len - i);
413062306a36Sopenharmony_ci			memcpy(data + i, value, copy_len);
413162306a36Sopenharmony_ci		}
413262306a36Sopenharmony_ci	}
413362306a36Sopenharmony_ci	return 0;
413462306a36Sopenharmony_ci}
413562306a36Sopenharmony_ci
413662306a36Sopenharmony_cistatic const struct ethtool_ops ice_ethtool_ops = {
413762306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
413862306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE |
413962306a36Sopenharmony_ci				     ETHTOOL_COALESCE_RX_USECS_HIGH,
414062306a36Sopenharmony_ci	.get_link_ksettings	= ice_get_link_ksettings,
414162306a36Sopenharmony_ci	.set_link_ksettings	= ice_set_link_ksettings,
414262306a36Sopenharmony_ci	.get_drvinfo		= ice_get_drvinfo,
414362306a36Sopenharmony_ci	.get_regs_len		= ice_get_regs_len,
414462306a36Sopenharmony_ci	.get_regs		= ice_get_regs,
414562306a36Sopenharmony_ci	.get_wol		= ice_get_wol,
414662306a36Sopenharmony_ci	.set_wol		= ice_set_wol,
414762306a36Sopenharmony_ci	.get_msglevel		= ice_get_msglevel,
414862306a36Sopenharmony_ci	.set_msglevel		= ice_set_msglevel,
414962306a36Sopenharmony_ci	.self_test		= ice_self_test,
415062306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
415162306a36Sopenharmony_ci	.get_eeprom_len		= ice_get_eeprom_len,
415262306a36Sopenharmony_ci	.get_eeprom		= ice_get_eeprom,
415362306a36Sopenharmony_ci	.get_coalesce		= ice_get_coalesce,
415462306a36Sopenharmony_ci	.set_coalesce		= ice_set_coalesce,
415562306a36Sopenharmony_ci	.get_strings		= ice_get_strings,
415662306a36Sopenharmony_ci	.set_phys_id		= ice_set_phys_id,
415762306a36Sopenharmony_ci	.get_ethtool_stats      = ice_get_ethtool_stats,
415862306a36Sopenharmony_ci	.get_priv_flags		= ice_get_priv_flags,
415962306a36Sopenharmony_ci	.set_priv_flags		= ice_set_priv_flags,
416062306a36Sopenharmony_ci	.get_sset_count		= ice_get_sset_count,
416162306a36Sopenharmony_ci	.get_rxnfc		= ice_get_rxnfc,
416262306a36Sopenharmony_ci	.set_rxnfc		= ice_set_rxnfc,
416362306a36Sopenharmony_ci	.get_ringparam		= ice_get_ringparam,
416462306a36Sopenharmony_ci	.set_ringparam		= ice_set_ringparam,
416562306a36Sopenharmony_ci	.nway_reset		= ice_nway_reset,
416662306a36Sopenharmony_ci	.get_pauseparam		= ice_get_pauseparam,
416762306a36Sopenharmony_ci	.set_pauseparam		= ice_set_pauseparam,
416862306a36Sopenharmony_ci	.get_rxfh_key_size	= ice_get_rxfh_key_size,
416962306a36Sopenharmony_ci	.get_rxfh_indir_size	= ice_get_rxfh_indir_size,
417062306a36Sopenharmony_ci	.get_rxfh_context	= ice_get_rxfh_context,
417162306a36Sopenharmony_ci	.get_rxfh		= ice_get_rxfh,
417262306a36Sopenharmony_ci	.set_rxfh		= ice_set_rxfh,
417362306a36Sopenharmony_ci	.get_channels		= ice_get_channels,
417462306a36Sopenharmony_ci	.set_channels		= ice_set_channels,
417562306a36Sopenharmony_ci	.get_ts_info		= ice_get_ts_info,
417662306a36Sopenharmony_ci	.get_per_queue_coalesce	= ice_get_per_q_coalesce,
417762306a36Sopenharmony_ci	.set_per_queue_coalesce	= ice_set_per_q_coalesce,
417862306a36Sopenharmony_ci	.get_fecparam		= ice_get_fecparam,
417962306a36Sopenharmony_ci	.set_fecparam		= ice_set_fecparam,
418062306a36Sopenharmony_ci	.get_module_info	= ice_get_module_info,
418162306a36Sopenharmony_ci	.get_module_eeprom	= ice_get_module_eeprom,
418262306a36Sopenharmony_ci};
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_cistatic const struct ethtool_ops ice_ethtool_safe_mode_ops = {
418562306a36Sopenharmony_ci	.get_link_ksettings	= ice_get_link_ksettings,
418662306a36Sopenharmony_ci	.set_link_ksettings	= ice_set_link_ksettings,
418762306a36Sopenharmony_ci	.get_drvinfo		= ice_get_drvinfo,
418862306a36Sopenharmony_ci	.get_regs_len		= ice_get_regs_len,
418962306a36Sopenharmony_ci	.get_regs		= ice_get_regs,
419062306a36Sopenharmony_ci	.get_wol		= ice_get_wol,
419162306a36Sopenharmony_ci	.set_wol		= ice_set_wol,
419262306a36Sopenharmony_ci	.get_msglevel		= ice_get_msglevel,
419362306a36Sopenharmony_ci	.set_msglevel		= ice_set_msglevel,
419462306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
419562306a36Sopenharmony_ci	.get_eeprom_len		= ice_get_eeprom_len,
419662306a36Sopenharmony_ci	.get_eeprom		= ice_get_eeprom,
419762306a36Sopenharmony_ci	.get_strings		= ice_get_strings,
419862306a36Sopenharmony_ci	.get_ethtool_stats	= ice_get_ethtool_stats,
419962306a36Sopenharmony_ci	.get_sset_count		= ice_get_sset_count,
420062306a36Sopenharmony_ci	.get_ringparam		= ice_get_ringparam,
420162306a36Sopenharmony_ci	.set_ringparam		= ice_set_ringparam,
420262306a36Sopenharmony_ci	.nway_reset		= ice_nway_reset,
420362306a36Sopenharmony_ci	.get_channels		= ice_get_channels,
420462306a36Sopenharmony_ci};
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci/**
420762306a36Sopenharmony_ci * ice_set_ethtool_safe_mode_ops - setup safe mode ethtool ops
420862306a36Sopenharmony_ci * @netdev: network interface device structure
420962306a36Sopenharmony_ci */
421062306a36Sopenharmony_civoid ice_set_ethtool_safe_mode_ops(struct net_device *netdev)
421162306a36Sopenharmony_ci{
421262306a36Sopenharmony_ci	netdev->ethtool_ops = &ice_ethtool_safe_mode_ops;
421362306a36Sopenharmony_ci}
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_cistatic const struct ethtool_ops ice_ethtool_repr_ops = {
421662306a36Sopenharmony_ci	.get_drvinfo		= ice_repr_get_drvinfo,
421762306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
421862306a36Sopenharmony_ci	.get_strings		= ice_repr_get_strings,
421962306a36Sopenharmony_ci	.get_ethtool_stats      = ice_repr_get_ethtool_stats,
422062306a36Sopenharmony_ci	.get_sset_count		= ice_repr_get_sset_count,
422162306a36Sopenharmony_ci};
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci/**
422462306a36Sopenharmony_ci * ice_set_ethtool_repr_ops - setup VF's port representor ethtool ops
422562306a36Sopenharmony_ci * @netdev: network interface device structure
422662306a36Sopenharmony_ci */
422762306a36Sopenharmony_civoid ice_set_ethtool_repr_ops(struct net_device *netdev)
422862306a36Sopenharmony_ci{
422962306a36Sopenharmony_ci	netdev->ethtool_ops = &ice_ethtool_repr_ops;
423062306a36Sopenharmony_ci}
423162306a36Sopenharmony_ci
423262306a36Sopenharmony_ci/**
423362306a36Sopenharmony_ci * ice_set_ethtool_ops - setup netdev ethtool ops
423462306a36Sopenharmony_ci * @netdev: network interface device structure
423562306a36Sopenharmony_ci *
423662306a36Sopenharmony_ci * setup netdev ethtool ops with ice specific ops
423762306a36Sopenharmony_ci */
423862306a36Sopenharmony_civoid ice_set_ethtool_ops(struct net_device *netdev)
423962306a36Sopenharmony_ci{
424062306a36Sopenharmony_ci	netdev->ethtool_ops = &ice_ethtool_ops;
424162306a36Sopenharmony_ci}
4242