162306a36Sopenharmony_ci/* Broadcom NetXtreme-C/E network driver.
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Copyright (c) 2014-2016 Broadcom Corporation
462306a36Sopenharmony_ci * Copyright (c) 2016-2017 Broadcom Limited
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
762306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
862306a36Sopenharmony_ci * the Free Software Foundation.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/ctype.h>
1262306a36Sopenharmony_ci#include <linux/stringify.h>
1362306a36Sopenharmony_ci#include <linux/ethtool.h>
1462306a36Sopenharmony_ci#include <linux/ethtool_netlink.h>
1562306a36Sopenharmony_ci#include <linux/linkmode.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/pci.h>
1862306a36Sopenharmony_ci#include <linux/etherdevice.h>
1962306a36Sopenharmony_ci#include <linux/crc32.h>
2062306a36Sopenharmony_ci#include <linux/firmware.h>
2162306a36Sopenharmony_ci#include <linux/utsname.h>
2262306a36Sopenharmony_ci#include <linux/time.h>
2362306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
2462306a36Sopenharmony_ci#include <linux/net_tstamp.h>
2562306a36Sopenharmony_ci#include <linux/timecounter.h>
2662306a36Sopenharmony_ci#include <net/netlink.h>
2762306a36Sopenharmony_ci#include "bnxt_hsi.h"
2862306a36Sopenharmony_ci#include "bnxt.h"
2962306a36Sopenharmony_ci#include "bnxt_hwrm.h"
3062306a36Sopenharmony_ci#include "bnxt_ulp.h"
3162306a36Sopenharmony_ci#include "bnxt_xdp.h"
3262306a36Sopenharmony_ci#include "bnxt_ptp.h"
3362306a36Sopenharmony_ci#include "bnxt_ethtool.h"
3462306a36Sopenharmony_ci#include "bnxt_nvm_defs.h"	/* NVRAM content constant and structure defs */
3562306a36Sopenharmony_ci#include "bnxt_fw_hdr.h"	/* Firmware hdr constant and structure defs */
3662306a36Sopenharmony_ci#include "bnxt_coredump.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define BNXT_NVM_ERR_MSG(dev, extack, msg)			\
3962306a36Sopenharmony_ci	do {							\
4062306a36Sopenharmony_ci		if (extack)					\
4162306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, msg);	\
4262306a36Sopenharmony_ci		netdev_err(dev, "%s\n", msg);			\
4362306a36Sopenharmony_ci	} while (0)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic u32 bnxt_get_msglevel(struct net_device *dev)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return bp->msg_enable;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void bnxt_set_msglevel(struct net_device *dev, u32 value)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	bp->msg_enable = value;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int bnxt_get_coalesce(struct net_device *dev,
6062306a36Sopenharmony_ci			     struct ethtool_coalesce *coal,
6162306a36Sopenharmony_ci			     struct kernel_ethtool_coalesce *kernel_coal,
6262306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
6562306a36Sopenharmony_ci	struct bnxt_coal *hw_coal;
6662306a36Sopenharmony_ci	u16 mult;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	memset(coal, 0, sizeof(*coal));
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	hw_coal = &bp->rx_coal;
7362306a36Sopenharmony_ci	mult = hw_coal->bufs_per_record;
7462306a36Sopenharmony_ci	coal->rx_coalesce_usecs = hw_coal->coal_ticks;
7562306a36Sopenharmony_ci	coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult;
7662306a36Sopenharmony_ci	coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq;
7762306a36Sopenharmony_ci	coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult;
7862306a36Sopenharmony_ci	if (hw_coal->flags &
7962306a36Sopenharmony_ci	    RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET)
8062306a36Sopenharmony_ci		kernel_coal->use_cqe_mode_rx = true;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	hw_coal = &bp->tx_coal;
8362306a36Sopenharmony_ci	mult = hw_coal->bufs_per_record;
8462306a36Sopenharmony_ci	coal->tx_coalesce_usecs = hw_coal->coal_ticks;
8562306a36Sopenharmony_ci	coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult;
8662306a36Sopenharmony_ci	coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq;
8762306a36Sopenharmony_ci	coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult;
8862306a36Sopenharmony_ci	if (hw_coal->flags &
8962306a36Sopenharmony_ci	    RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET)
9062306a36Sopenharmony_ci		kernel_coal->use_cqe_mode_tx = true;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	coal->stats_block_coalesce_usecs = bp->stats_coal_ticks;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int bnxt_set_coalesce(struct net_device *dev,
9862306a36Sopenharmony_ci			     struct ethtool_coalesce *coal,
9962306a36Sopenharmony_ci			     struct kernel_ethtool_coalesce *kernel_coal,
10062306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
10362306a36Sopenharmony_ci	bool update_stats = false;
10462306a36Sopenharmony_ci	struct bnxt_coal *hw_coal;
10562306a36Sopenharmony_ci	int rc = 0;
10662306a36Sopenharmony_ci	u16 mult;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (coal->use_adaptive_rx_coalesce) {
10962306a36Sopenharmony_ci		bp->flags |= BNXT_FLAG_DIM;
11062306a36Sopenharmony_ci	} else {
11162306a36Sopenharmony_ci		if (bp->flags & BNXT_FLAG_DIM) {
11262306a36Sopenharmony_ci			bp->flags &= ~(BNXT_FLAG_DIM);
11362306a36Sopenharmony_ci			goto reset_coalesce;
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) &&
11862306a36Sopenharmony_ci	    !(bp->coal_cap.cmpl_params &
11962306a36Sopenharmony_ci	      RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET))
12062306a36Sopenharmony_ci		return -EOPNOTSUPP;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	hw_coal = &bp->rx_coal;
12362306a36Sopenharmony_ci	mult = hw_coal->bufs_per_record;
12462306a36Sopenharmony_ci	hw_coal->coal_ticks = coal->rx_coalesce_usecs;
12562306a36Sopenharmony_ci	hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult;
12662306a36Sopenharmony_ci	hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq;
12762306a36Sopenharmony_ci	hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult;
12862306a36Sopenharmony_ci	hw_coal->flags &=
12962306a36Sopenharmony_ci		~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
13062306a36Sopenharmony_ci	if (kernel_coal->use_cqe_mode_rx)
13162306a36Sopenharmony_ci		hw_coal->flags |=
13262306a36Sopenharmony_ci			RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	hw_coal = &bp->tx_coal;
13562306a36Sopenharmony_ci	mult = hw_coal->bufs_per_record;
13662306a36Sopenharmony_ci	hw_coal->coal_ticks = coal->tx_coalesce_usecs;
13762306a36Sopenharmony_ci	hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult;
13862306a36Sopenharmony_ci	hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq;
13962306a36Sopenharmony_ci	hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult;
14062306a36Sopenharmony_ci	hw_coal->flags &=
14162306a36Sopenharmony_ci		~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
14262306a36Sopenharmony_ci	if (kernel_coal->use_cqe_mode_tx)
14362306a36Sopenharmony_ci		hw_coal->flags |=
14462306a36Sopenharmony_ci			RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) {
14762306a36Sopenharmony_ci		u32 stats_ticks = coal->stats_block_coalesce_usecs;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		/* Allow 0, which means disable. */
15062306a36Sopenharmony_ci		if (stats_ticks)
15162306a36Sopenharmony_ci			stats_ticks = clamp_t(u32, stats_ticks,
15262306a36Sopenharmony_ci					      BNXT_MIN_STATS_COAL_TICKS,
15362306a36Sopenharmony_ci					      BNXT_MAX_STATS_COAL_TICKS);
15462306a36Sopenharmony_ci		stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS);
15562306a36Sopenharmony_ci		bp->stats_coal_ticks = stats_ticks;
15662306a36Sopenharmony_ci		if (bp->stats_coal_ticks)
15762306a36Sopenharmony_ci			bp->current_interval =
15862306a36Sopenharmony_ci				bp->stats_coal_ticks * HZ / 1000000;
15962306a36Sopenharmony_ci		else
16062306a36Sopenharmony_ci			bp->current_interval = BNXT_TIMER_INTERVAL;
16162306a36Sopenharmony_ci		update_stats = true;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cireset_coalesce:
16562306a36Sopenharmony_ci	if (test_bit(BNXT_STATE_OPEN, &bp->state)) {
16662306a36Sopenharmony_ci		if (update_stats) {
16762306a36Sopenharmony_ci			bnxt_close_nic(bp, true, false);
16862306a36Sopenharmony_ci			rc = bnxt_open_nic(bp, true, false);
16962306a36Sopenharmony_ci		} else {
17062306a36Sopenharmony_ci			rc = bnxt_hwrm_set_coal(bp);
17162306a36Sopenharmony_ci		}
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return rc;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic const char * const bnxt_ring_rx_stats_str[] = {
17862306a36Sopenharmony_ci	"rx_ucast_packets",
17962306a36Sopenharmony_ci	"rx_mcast_packets",
18062306a36Sopenharmony_ci	"rx_bcast_packets",
18162306a36Sopenharmony_ci	"rx_discards",
18262306a36Sopenharmony_ci	"rx_errors",
18362306a36Sopenharmony_ci	"rx_ucast_bytes",
18462306a36Sopenharmony_ci	"rx_mcast_bytes",
18562306a36Sopenharmony_ci	"rx_bcast_bytes",
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic const char * const bnxt_ring_tx_stats_str[] = {
18962306a36Sopenharmony_ci	"tx_ucast_packets",
19062306a36Sopenharmony_ci	"tx_mcast_packets",
19162306a36Sopenharmony_ci	"tx_bcast_packets",
19262306a36Sopenharmony_ci	"tx_errors",
19362306a36Sopenharmony_ci	"tx_discards",
19462306a36Sopenharmony_ci	"tx_ucast_bytes",
19562306a36Sopenharmony_ci	"tx_mcast_bytes",
19662306a36Sopenharmony_ci	"tx_bcast_bytes",
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic const char * const bnxt_ring_tpa_stats_str[] = {
20062306a36Sopenharmony_ci	"tpa_packets",
20162306a36Sopenharmony_ci	"tpa_bytes",
20262306a36Sopenharmony_ci	"tpa_events",
20362306a36Sopenharmony_ci	"tpa_aborts",
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic const char * const bnxt_ring_tpa2_stats_str[] = {
20762306a36Sopenharmony_ci	"rx_tpa_eligible_pkt",
20862306a36Sopenharmony_ci	"rx_tpa_eligible_bytes",
20962306a36Sopenharmony_ci	"rx_tpa_pkt",
21062306a36Sopenharmony_ci	"rx_tpa_bytes",
21162306a36Sopenharmony_ci	"rx_tpa_errors",
21262306a36Sopenharmony_ci	"rx_tpa_events",
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic const char * const bnxt_rx_sw_stats_str[] = {
21662306a36Sopenharmony_ci	"rx_l4_csum_errors",
21762306a36Sopenharmony_ci	"rx_resets",
21862306a36Sopenharmony_ci	"rx_buf_errors",
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic const char * const bnxt_cmn_sw_stats_str[] = {
22262306a36Sopenharmony_ci	"missed_irqs",
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci#define BNXT_RX_STATS_ENTRY(counter)	\
22662306a36Sopenharmony_ci	{ BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#define BNXT_TX_STATS_ENTRY(counter)	\
22962306a36Sopenharmony_ci	{ BNXT_TX_STATS_OFFSET(counter), __stringify(counter) }
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_ENTRY(counter)	\
23262306a36Sopenharmony_ci	{ BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) }
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_ENTRY(counter)	\
23562306a36Sopenharmony_ci	{ BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) }
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRY(n)				\
23862306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us),	\
23962306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions)
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRY(n)				\
24262306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us),	\
24362306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions)
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRIES				\
24662306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(0),				\
24762306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(1),				\
24862306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(2),				\
24962306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(3),				\
25062306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(4),				\
25162306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(5),				\
25262306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(6),				\
25362306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(7)
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRIES				\
25662306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(0),				\
25762306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(1),				\
25862306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(2),				\
25962306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(3),				\
26062306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(4),				\
26162306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(5),				\
26262306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(6),				\
26362306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(7)
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRY(n)				\
26662306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n),		\
26762306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n)
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRY(n)				\
27062306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n),		\
27162306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n)
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRIES				\
27462306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(0),				\
27562306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(1),				\
27662306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(2),				\
27762306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(3),				\
27862306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(4),				\
27962306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(5),				\
28062306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(6),				\
28162306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(7)				\
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRIES				\
28462306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(0),				\
28562306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(1),				\
28662306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(2),				\
28762306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(3),				\
28862306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(4),				\
28962306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(5),				\
29062306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(6),				\
29162306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(7)				\
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n)			\
29462306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n),	\
29562306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n)
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES				\
29862306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0),				\
29962306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1),				\
30062306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2),				\
30162306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3),				\
30262306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4),				\
30362306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5),				\
30462306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6),				\
30562306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7)
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRY(counter, n)		\
30862306a36Sopenharmony_ci	{ BNXT_RX_STATS_EXT_OFFSET(counter##_cos0),	\
30962306a36Sopenharmony_ci	  __stringify(counter##_pri##n) }
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRY(counter, n)		\
31262306a36Sopenharmony_ci	{ BNXT_TX_STATS_EXT_OFFSET(counter##_cos0),	\
31362306a36Sopenharmony_ci	  __stringify(counter##_pri##n) }
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRIES(counter)		\
31662306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 0),		\
31762306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 1),		\
31862306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 2),		\
31962306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 3),		\
32062306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 4),		\
32162306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 5),		\
32262306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 6),		\
32362306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 7)
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRIES(counter)		\
32662306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 0),		\
32762306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 1),		\
32862306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 2),		\
32962306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 3),		\
33062306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 4),		\
33162306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 5),		\
33262306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 6),		\
33362306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 7)
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cienum {
33662306a36Sopenharmony_ci	RX_TOTAL_DISCARDS,
33762306a36Sopenharmony_ci	TX_TOTAL_DISCARDS,
33862306a36Sopenharmony_ci	RX_NETPOLL_DISCARDS,
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic const char *const bnxt_ring_err_stats_arr[] = {
34262306a36Sopenharmony_ci	"rx_total_l4_csum_errors",
34362306a36Sopenharmony_ci	"rx_total_resets",
34462306a36Sopenharmony_ci	"rx_total_buf_errors",
34562306a36Sopenharmony_ci	"rx_total_oom_discards",
34662306a36Sopenharmony_ci	"rx_total_netpoll_discards",
34762306a36Sopenharmony_ci	"rx_total_ring_discards",
34862306a36Sopenharmony_ci	"tx_total_resets",
34962306a36Sopenharmony_ci	"tx_total_ring_discards",
35062306a36Sopenharmony_ci	"total_missed_irqs",
35162306a36Sopenharmony_ci};
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci#define NUM_RING_RX_SW_STATS		ARRAY_SIZE(bnxt_rx_sw_stats_str)
35462306a36Sopenharmony_ci#define NUM_RING_CMN_SW_STATS		ARRAY_SIZE(bnxt_cmn_sw_stats_str)
35562306a36Sopenharmony_ci#define NUM_RING_RX_HW_STATS		ARRAY_SIZE(bnxt_ring_rx_stats_str)
35662306a36Sopenharmony_ci#define NUM_RING_TX_HW_STATS		ARRAY_SIZE(bnxt_ring_tx_stats_str)
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic const struct {
35962306a36Sopenharmony_ci	long offset;
36062306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
36162306a36Sopenharmony_ci} bnxt_port_stats_arr[] = {
36262306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_64b_frames),
36362306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_65b_127b_frames),
36462306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_128b_255b_frames),
36562306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_256b_511b_frames),
36662306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames),
36762306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames),
36862306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_good_vlan_frames),
36962306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames),
37062306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames),
37162306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames),
37262306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames),
37362306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_total_frames),
37462306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_ucast_frames),
37562306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_mcast_frames),
37662306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_bcast_frames),
37762306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_fcs_err_frames),
37862306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_ctrl_frames),
37962306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pause_frames),
38062306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_frames),
38162306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_align_err_frames),
38262306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_ovrsz_frames),
38362306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_jbr_frames),
38462306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_mtu_err_frames),
38562306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_tagged_frames),
38662306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_double_tagged_frames),
38762306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_good_frames),
38862306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0),
38962306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1),
39062306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2),
39162306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3),
39262306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4),
39362306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5),
39462306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6),
39562306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7),
39662306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_undrsz_frames),
39762306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_eee_lpi_events),
39862306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration),
39962306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_bytes),
40062306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_runt_bytes),
40162306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_runt_frames),
40262306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_stat_discard),
40362306a36Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_stat_err),
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_64b_frames),
40662306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_65b_127b_frames),
40762306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_128b_255b_frames),
40862306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_256b_511b_frames),
40962306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames),
41062306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames),
41162306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_good_vlan_frames),
41262306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames),
41362306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames),
41462306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames),
41562306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames),
41662306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_good_frames),
41762306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_total_frames),
41862306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_ucast_frames),
41962306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_mcast_frames),
42062306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_bcast_frames),
42162306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pause_frames),
42262306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_frames),
42362306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_jabber_frames),
42462306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_fcs_err_frames),
42562306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_err),
42662306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_fifo_underruns),
42762306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0),
42862306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1),
42962306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2),
43062306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3),
43162306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4),
43262306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5),
43362306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6),
43462306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7),
43562306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_eee_lpi_events),
43662306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration),
43762306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_total_collisions),
43862306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_bytes),
43962306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_xthol_frames),
44062306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_stat_discard),
44162306a36Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_stat_error),
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic const struct {
44562306a36Sopenharmony_ci	long offset;
44662306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
44762306a36Sopenharmony_ci} bnxt_port_stats_ext_arr[] = {
44862306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(link_down_events),
44962306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events),
45062306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(resume_pause_events),
45162306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events),
45262306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events),
45362306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRIES,
45462306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRIES,
45562306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_bits),
45662306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold),
45762306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err),
45862306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits),
45962306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES,
46062306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks),
46162306a36Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks),
46262306a36Sopenharmony_ci};
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic const struct {
46562306a36Sopenharmony_ci	long offset;
46662306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
46762306a36Sopenharmony_ci} bnxt_tx_port_stats_ext_arr[] = {
46862306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRIES,
46962306a36Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRIES,
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic const struct {
47362306a36Sopenharmony_ci	long base_off;
47462306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
47562306a36Sopenharmony_ci} bnxt_rx_bytes_pri_arr[] = {
47662306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRIES(rx_bytes),
47762306a36Sopenharmony_ci};
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic const struct {
48062306a36Sopenharmony_ci	long base_off;
48162306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
48262306a36Sopenharmony_ci} bnxt_rx_pkts_pri_arr[] = {
48362306a36Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRIES(rx_packets),
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic const struct {
48762306a36Sopenharmony_ci	long base_off;
48862306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
48962306a36Sopenharmony_ci} bnxt_tx_bytes_pri_arr[] = {
49062306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRIES(tx_bytes),
49162306a36Sopenharmony_ci};
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic const struct {
49462306a36Sopenharmony_ci	long base_off;
49562306a36Sopenharmony_ci	char string[ETH_GSTRING_LEN];
49662306a36Sopenharmony_ci} bnxt_tx_pkts_pri_arr[] = {
49762306a36Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRIES(tx_packets),
49862306a36Sopenharmony_ci};
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci#define BNXT_NUM_RING_ERR_STATS	ARRAY_SIZE(bnxt_ring_err_stats_arr)
50162306a36Sopenharmony_ci#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
50262306a36Sopenharmony_ci#define BNXT_NUM_STATS_PRI			\
50362306a36Sopenharmony_ci	(ARRAY_SIZE(bnxt_rx_bytes_pri_arr) +	\
50462306a36Sopenharmony_ci	 ARRAY_SIZE(bnxt_rx_pkts_pri_arr) +	\
50562306a36Sopenharmony_ci	 ARRAY_SIZE(bnxt_tx_bytes_pri_arr) +	\
50662306a36Sopenharmony_ci	 ARRAY_SIZE(bnxt_tx_pkts_pri_arr))
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int bnxt_get_num_tpa_ring_stats(struct bnxt *bp)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	if (BNXT_SUPPORTS_TPA(bp)) {
51162306a36Sopenharmony_ci		if (bp->max_tpa_v2) {
51262306a36Sopenharmony_ci			if (BNXT_CHIP_P5_THOR(bp))
51362306a36Sopenharmony_ci				return BNXT_NUM_TPA_RING_STATS_P5;
51462306a36Sopenharmony_ci			return BNXT_NUM_TPA_RING_STATS_P5_SR2;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci		return BNXT_NUM_TPA_RING_STATS;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci	return 0;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int bnxt_get_num_ring_stats(struct bnxt *bp)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	int rx, tx, cmn;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS +
52662306a36Sopenharmony_ci	     bnxt_get_num_tpa_ring_stats(bp);
52762306a36Sopenharmony_ci	tx = NUM_RING_TX_HW_STATS;
52862306a36Sopenharmony_ci	cmn = NUM_RING_CMN_SW_STATS;
52962306a36Sopenharmony_ci	return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
53062306a36Sopenharmony_ci	       cmn * bp->cp_nr_rings;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic int bnxt_get_num_stats(struct bnxt *bp)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	int num_stats = bnxt_get_num_ring_stats(bp);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	num_stats += BNXT_NUM_RING_ERR_STATS;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS)
54062306a36Sopenharmony_ci		num_stats += BNXT_NUM_PORT_STATS;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
54362306a36Sopenharmony_ci		num_stats += bp->fw_rx_stats_ext_size +
54462306a36Sopenharmony_ci			     bp->fw_tx_stats_ext_size;
54562306a36Sopenharmony_ci		if (bp->pri2cos_valid)
54662306a36Sopenharmony_ci			num_stats += BNXT_NUM_STATS_PRI;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	return num_stats;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic int bnxt_get_sset_count(struct net_device *dev, int sset)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	switch (sset) {
55762306a36Sopenharmony_ci	case ETH_SS_STATS:
55862306a36Sopenharmony_ci		return bnxt_get_num_stats(bp);
55962306a36Sopenharmony_ci	case ETH_SS_TEST:
56062306a36Sopenharmony_ci		if (!bp->num_tests)
56162306a36Sopenharmony_ci			return -EOPNOTSUPP;
56262306a36Sopenharmony_ci		return bp->num_tests;
56362306a36Sopenharmony_ci	default:
56462306a36Sopenharmony_ci		return -EOPNOTSUPP;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic bool is_rx_ring(struct bnxt *bp, int ring_num)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	return ring_num < bp->rx_nr_rings;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic bool is_tx_ring(struct bnxt *bp, int ring_num)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	int tx_base = 0;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (!(bp->flags & BNXT_FLAG_SHARED_RINGS))
57862306a36Sopenharmony_ci		tx_base = bp->rx_nr_rings;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings))
58162306a36Sopenharmony_ci		return true;
58262306a36Sopenharmony_ci	return false;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic void bnxt_get_ethtool_stats(struct net_device *dev,
58662306a36Sopenharmony_ci				   struct ethtool_stats *stats, u64 *buf)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct bnxt_total_ring_err_stats ring_err_stats = {0};
58962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
59062306a36Sopenharmony_ci	u64 *curr, *prev;
59162306a36Sopenharmony_ci	u32 tpa_stats;
59262306a36Sopenharmony_ci	u32 i, j = 0;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (!bp->bnapi) {
59562306a36Sopenharmony_ci		j += bnxt_get_num_ring_stats(bp);
59662306a36Sopenharmony_ci		goto skip_ring_stats;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	tpa_stats = bnxt_get_num_tpa_ring_stats(bp);
60062306a36Sopenharmony_ci	for (i = 0; i < bp->cp_nr_rings; i++) {
60162306a36Sopenharmony_ci		struct bnxt_napi *bnapi = bp->bnapi[i];
60262306a36Sopenharmony_ci		struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
60362306a36Sopenharmony_ci		u64 *sw_stats = cpr->stats.sw_stats;
60462306a36Sopenharmony_ci		u64 *sw;
60562306a36Sopenharmony_ci		int k;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		if (is_rx_ring(bp, i)) {
60862306a36Sopenharmony_ci			for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++)
60962306a36Sopenharmony_ci				buf[j] = sw_stats[k];
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci		if (is_tx_ring(bp, i)) {
61262306a36Sopenharmony_ci			k = NUM_RING_RX_HW_STATS;
61362306a36Sopenharmony_ci			for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS;
61462306a36Sopenharmony_ci			       j++, k++)
61562306a36Sopenharmony_ci				buf[j] = sw_stats[k];
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci		if (!tpa_stats || !is_rx_ring(bp, i))
61862306a36Sopenharmony_ci			goto skip_tpa_ring_stats;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS;
62162306a36Sopenharmony_ci		for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS +
62262306a36Sopenharmony_ci			   tpa_stats; j++, k++)
62362306a36Sopenharmony_ci			buf[j] = sw_stats[k];
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciskip_tpa_ring_stats:
62662306a36Sopenharmony_ci		sw = (u64 *)&cpr->sw_stats.rx;
62762306a36Sopenharmony_ci		if (is_rx_ring(bp, i)) {
62862306a36Sopenharmony_ci			for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++)
62962306a36Sopenharmony_ci				buf[j] = sw[k];
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		sw = (u64 *)&cpr->sw_stats.cmn;
63362306a36Sopenharmony_ci		for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++)
63462306a36Sopenharmony_ci			buf[j] = sw[k];
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	bnxt_get_ring_err_stats(bp, &ring_err_stats);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ciskip_ring_stats:
64062306a36Sopenharmony_ci	curr = &ring_err_stats.rx_total_l4_csum_errors;
64162306a36Sopenharmony_ci	prev = &bp->ring_err_stats_prev.rx_total_l4_csum_errors;
64262306a36Sopenharmony_ci	for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++, j++, curr++, prev++)
64362306a36Sopenharmony_ci		buf[j] = *curr + *prev;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS) {
64662306a36Sopenharmony_ci		u64 *port_stats = bp->port_stats.sw_stats;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++)
64962306a36Sopenharmony_ci			buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset);
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
65262306a36Sopenharmony_ci		u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats;
65362306a36Sopenharmony_ci		u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) {
65662306a36Sopenharmony_ci			buf[j] = *(rx_port_stats_ext +
65762306a36Sopenharmony_ci				   bnxt_port_stats_ext_arr[i].offset);
65862306a36Sopenharmony_ci		}
65962306a36Sopenharmony_ci		for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) {
66062306a36Sopenharmony_ci			buf[j] = *(tx_port_stats_ext +
66162306a36Sopenharmony_ci				   bnxt_tx_port_stats_ext_arr[i].offset);
66262306a36Sopenharmony_ci		}
66362306a36Sopenharmony_ci		if (bp->pri2cos_valid) {
66462306a36Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
66562306a36Sopenharmony_ci				long n = bnxt_rx_bytes_pri_arr[i].base_off +
66662306a36Sopenharmony_ci					 bp->pri2cos_idx[i];
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci				buf[j] = *(rx_port_stats_ext + n);
66962306a36Sopenharmony_ci			}
67062306a36Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
67162306a36Sopenharmony_ci				long n = bnxt_rx_pkts_pri_arr[i].base_off +
67262306a36Sopenharmony_ci					 bp->pri2cos_idx[i];
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci				buf[j] = *(rx_port_stats_ext + n);
67562306a36Sopenharmony_ci			}
67662306a36Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
67762306a36Sopenharmony_ci				long n = bnxt_tx_bytes_pri_arr[i].base_off +
67862306a36Sopenharmony_ci					 bp->pri2cos_idx[i];
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci				buf[j] = *(tx_port_stats_ext + n);
68162306a36Sopenharmony_ci			}
68262306a36Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
68362306a36Sopenharmony_ci				long n = bnxt_tx_pkts_pri_arr[i].base_off +
68462306a36Sopenharmony_ci					 bp->pri2cos_idx[i];
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci				buf[j] = *(tx_port_stats_ext + n);
68762306a36Sopenharmony_ci			}
68862306a36Sopenharmony_ci		}
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
69562306a36Sopenharmony_ci	static const char * const *str;
69662306a36Sopenharmony_ci	u32 i, j, num_str;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	switch (stringset) {
69962306a36Sopenharmony_ci	case ETH_SS_STATS:
70062306a36Sopenharmony_ci		for (i = 0; i < bp->cp_nr_rings; i++) {
70162306a36Sopenharmony_ci			if (is_rx_ring(bp, i)) {
70262306a36Sopenharmony_ci				num_str = NUM_RING_RX_HW_STATS;
70362306a36Sopenharmony_ci				for (j = 0; j < num_str; j++) {
70462306a36Sopenharmony_ci					sprintf(buf, "[%d]: %s", i,
70562306a36Sopenharmony_ci						bnxt_ring_rx_stats_str[j]);
70662306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
70762306a36Sopenharmony_ci				}
70862306a36Sopenharmony_ci			}
70962306a36Sopenharmony_ci			if (is_tx_ring(bp, i)) {
71062306a36Sopenharmony_ci				num_str = NUM_RING_TX_HW_STATS;
71162306a36Sopenharmony_ci				for (j = 0; j < num_str; j++) {
71262306a36Sopenharmony_ci					sprintf(buf, "[%d]: %s", i,
71362306a36Sopenharmony_ci						bnxt_ring_tx_stats_str[j]);
71462306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
71562306a36Sopenharmony_ci				}
71662306a36Sopenharmony_ci			}
71762306a36Sopenharmony_ci			num_str = bnxt_get_num_tpa_ring_stats(bp);
71862306a36Sopenharmony_ci			if (!num_str || !is_rx_ring(bp, i))
71962306a36Sopenharmony_ci				goto skip_tpa_stats;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci			if (bp->max_tpa_v2)
72262306a36Sopenharmony_ci				str = bnxt_ring_tpa2_stats_str;
72362306a36Sopenharmony_ci			else
72462306a36Sopenharmony_ci				str = bnxt_ring_tpa_stats_str;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci			for (j = 0; j < num_str; j++) {
72762306a36Sopenharmony_ci				sprintf(buf, "[%d]: %s", i, str[j]);
72862306a36Sopenharmony_ci				buf += ETH_GSTRING_LEN;
72962306a36Sopenharmony_ci			}
73062306a36Sopenharmony_ciskip_tpa_stats:
73162306a36Sopenharmony_ci			if (is_rx_ring(bp, i)) {
73262306a36Sopenharmony_ci				num_str = NUM_RING_RX_SW_STATS;
73362306a36Sopenharmony_ci				for (j = 0; j < num_str; j++) {
73462306a36Sopenharmony_ci					sprintf(buf, "[%d]: %s", i,
73562306a36Sopenharmony_ci						bnxt_rx_sw_stats_str[j]);
73662306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
73762306a36Sopenharmony_ci				}
73862306a36Sopenharmony_ci			}
73962306a36Sopenharmony_ci			num_str = NUM_RING_CMN_SW_STATS;
74062306a36Sopenharmony_ci			for (j = 0; j < num_str; j++) {
74162306a36Sopenharmony_ci				sprintf(buf, "[%d]: %s", i,
74262306a36Sopenharmony_ci					bnxt_cmn_sw_stats_str[j]);
74362306a36Sopenharmony_ci				buf += ETH_GSTRING_LEN;
74462306a36Sopenharmony_ci			}
74562306a36Sopenharmony_ci		}
74662306a36Sopenharmony_ci		for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) {
74762306a36Sopenharmony_ci			strscpy(buf, bnxt_ring_err_stats_arr[i], ETH_GSTRING_LEN);
74862306a36Sopenharmony_ci			buf += ETH_GSTRING_LEN;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		if (bp->flags & BNXT_FLAG_PORT_STATS) {
75262306a36Sopenharmony_ci			for (i = 0; i < BNXT_NUM_PORT_STATS; i++) {
75362306a36Sopenharmony_ci				strcpy(buf, bnxt_port_stats_arr[i].string);
75462306a36Sopenharmony_ci				buf += ETH_GSTRING_LEN;
75562306a36Sopenharmony_ci			}
75662306a36Sopenharmony_ci		}
75762306a36Sopenharmony_ci		if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
75862306a36Sopenharmony_ci			for (i = 0; i < bp->fw_rx_stats_ext_size; i++) {
75962306a36Sopenharmony_ci				strcpy(buf, bnxt_port_stats_ext_arr[i].string);
76062306a36Sopenharmony_ci				buf += ETH_GSTRING_LEN;
76162306a36Sopenharmony_ci			}
76262306a36Sopenharmony_ci			for (i = 0; i < bp->fw_tx_stats_ext_size; i++) {
76362306a36Sopenharmony_ci				strcpy(buf,
76462306a36Sopenharmony_ci				       bnxt_tx_port_stats_ext_arr[i].string);
76562306a36Sopenharmony_ci				buf += ETH_GSTRING_LEN;
76662306a36Sopenharmony_ci			}
76762306a36Sopenharmony_ci			if (bp->pri2cos_valid) {
76862306a36Sopenharmony_ci				for (i = 0; i < 8; i++) {
76962306a36Sopenharmony_ci					strcpy(buf,
77062306a36Sopenharmony_ci					       bnxt_rx_bytes_pri_arr[i].string);
77162306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
77262306a36Sopenharmony_ci				}
77362306a36Sopenharmony_ci				for (i = 0; i < 8; i++) {
77462306a36Sopenharmony_ci					strcpy(buf,
77562306a36Sopenharmony_ci					       bnxt_rx_pkts_pri_arr[i].string);
77662306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
77762306a36Sopenharmony_ci				}
77862306a36Sopenharmony_ci				for (i = 0; i < 8; i++) {
77962306a36Sopenharmony_ci					strcpy(buf,
78062306a36Sopenharmony_ci					       bnxt_tx_bytes_pri_arr[i].string);
78162306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
78262306a36Sopenharmony_ci				}
78362306a36Sopenharmony_ci				for (i = 0; i < 8; i++) {
78462306a36Sopenharmony_ci					strcpy(buf,
78562306a36Sopenharmony_ci					       bnxt_tx_pkts_pri_arr[i].string);
78662306a36Sopenharmony_ci					buf += ETH_GSTRING_LEN;
78762306a36Sopenharmony_ci				}
78862306a36Sopenharmony_ci			}
78962306a36Sopenharmony_ci		}
79062306a36Sopenharmony_ci		break;
79162306a36Sopenharmony_ci	case ETH_SS_TEST:
79262306a36Sopenharmony_ci		if (bp->num_tests)
79362306a36Sopenharmony_ci			memcpy(buf, bp->test_info->string,
79462306a36Sopenharmony_ci			       bp->num_tests * ETH_GSTRING_LEN);
79562306a36Sopenharmony_ci		break;
79662306a36Sopenharmony_ci	default:
79762306a36Sopenharmony_ci		netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n",
79862306a36Sopenharmony_ci			   stringset);
79962306a36Sopenharmony_ci		break;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic void bnxt_get_ringparam(struct net_device *dev,
80462306a36Sopenharmony_ci			       struct ethtool_ringparam *ering,
80562306a36Sopenharmony_ci			       struct kernel_ethtool_ringparam *kernel_ering,
80662306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_AGG_RINGS) {
81162306a36Sopenharmony_ci		ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT_JUM_ENA;
81262306a36Sopenharmony_ci		ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT;
81362306a36Sopenharmony_ci		kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
81462306a36Sopenharmony_ci	} else {
81562306a36Sopenharmony_ci		ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT;
81662306a36Sopenharmony_ci		ering->rx_jumbo_max_pending = 0;
81762306a36Sopenharmony_ci		kernel_ering->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	ering->rx_pending = bp->rx_ring_size;
82262306a36Sopenharmony_ci	ering->rx_jumbo_pending = bp->rx_agg_ring_size;
82362306a36Sopenharmony_ci	ering->tx_pending = bp->tx_ring_size;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int bnxt_set_ringparam(struct net_device *dev,
82762306a36Sopenharmony_ci			      struct ethtool_ringparam *ering,
82862306a36Sopenharmony_ci			      struct kernel_ethtool_ringparam *kernel_ering,
82962306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) ||
83462306a36Sopenharmony_ci	    (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) ||
83562306a36Sopenharmony_ci	    (ering->tx_pending < BNXT_MIN_TX_DESC_CNT))
83662306a36Sopenharmony_ci		return -EINVAL;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (netif_running(dev))
83962306a36Sopenharmony_ci		bnxt_close_nic(bp, false, false);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	bp->rx_ring_size = ering->rx_pending;
84262306a36Sopenharmony_ci	bp->tx_ring_size = ering->tx_pending;
84362306a36Sopenharmony_ci	bnxt_set_ring_params(bp);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (netif_running(dev))
84662306a36Sopenharmony_ci		return bnxt_open_nic(bp, false, false);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return 0;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic void bnxt_get_channels(struct net_device *dev,
85262306a36Sopenharmony_ci			      struct ethtool_channels *channel)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
85562306a36Sopenharmony_ci	struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
85662306a36Sopenharmony_ci	int max_rx_rings, max_tx_rings, tcs;
85762306a36Sopenharmony_ci	int max_tx_sch_inputs, tx_grps;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/* Get the most up-to-date max_tx_sch_inputs. */
86062306a36Sopenharmony_ci	if (netif_running(dev) && BNXT_NEW_RM(bp))
86162306a36Sopenharmony_ci		bnxt_hwrm_func_resc_qcaps(bp, false);
86262306a36Sopenharmony_ci	max_tx_sch_inputs = hw_resc->max_tx_sch_inputs;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true);
86562306a36Sopenharmony_ci	if (max_tx_sch_inputs)
86662306a36Sopenharmony_ci		max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	tcs = netdev_get_num_tc(dev);
86962306a36Sopenharmony_ci	tx_grps = max(tcs, 1);
87062306a36Sopenharmony_ci	if (bp->tx_nr_rings_xdp)
87162306a36Sopenharmony_ci		tx_grps++;
87262306a36Sopenharmony_ci	max_tx_rings /= tx_grps;
87362306a36Sopenharmony_ci	channel->max_combined = min_t(int, max_rx_rings, max_tx_rings);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) {
87662306a36Sopenharmony_ci		max_rx_rings = 0;
87762306a36Sopenharmony_ci		max_tx_rings = 0;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci	if (max_tx_sch_inputs)
88062306a36Sopenharmony_ci		max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (tcs > 1)
88362306a36Sopenharmony_ci		max_tx_rings /= tcs;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	channel->max_rx = max_rx_rings;
88662306a36Sopenharmony_ci	channel->max_tx = max_tx_rings;
88762306a36Sopenharmony_ci	channel->max_other = 0;
88862306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_SHARED_RINGS) {
88962306a36Sopenharmony_ci		channel->combined_count = bp->rx_nr_rings;
89062306a36Sopenharmony_ci		if (BNXT_CHIP_TYPE_NITRO_A0(bp))
89162306a36Sopenharmony_ci			channel->combined_count--;
89262306a36Sopenharmony_ci	} else {
89362306a36Sopenharmony_ci		if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) {
89462306a36Sopenharmony_ci			channel->rx_count = bp->rx_nr_rings;
89562306a36Sopenharmony_ci			channel->tx_count = bp->tx_nr_rings_per_tc;
89662306a36Sopenharmony_ci		}
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int bnxt_set_channels(struct net_device *dev,
90162306a36Sopenharmony_ci			     struct ethtool_channels *channel)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
90462306a36Sopenharmony_ci	int req_tx_rings, req_rx_rings, tcs;
90562306a36Sopenharmony_ci	bool sh = false;
90662306a36Sopenharmony_ci	int tx_xdp = 0;
90762306a36Sopenharmony_ci	int rc = 0;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if (channel->other_count)
91062306a36Sopenharmony_ci		return -EINVAL;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (!channel->combined_count &&
91362306a36Sopenharmony_ci	    (!channel->rx_count || !channel->tx_count))
91462306a36Sopenharmony_ci		return -EINVAL;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (channel->combined_count &&
91762306a36Sopenharmony_ci	    (channel->rx_count || channel->tx_count))
91862306a36Sopenharmony_ci		return -EINVAL;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count ||
92162306a36Sopenharmony_ci					    channel->tx_count))
92262306a36Sopenharmony_ci		return -EINVAL;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	if (channel->combined_count)
92562306a36Sopenharmony_ci		sh = true;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	tcs = netdev_get_num_tc(dev);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	req_tx_rings = sh ? channel->combined_count : channel->tx_count;
93062306a36Sopenharmony_ci	req_rx_rings = sh ? channel->combined_count : channel->rx_count;
93162306a36Sopenharmony_ci	if (bp->tx_nr_rings_xdp) {
93262306a36Sopenharmony_ci		if (!sh) {
93362306a36Sopenharmony_ci			netdev_err(dev, "Only combined mode supported when XDP is enabled.\n");
93462306a36Sopenharmony_ci			return -EINVAL;
93562306a36Sopenharmony_ci		}
93662306a36Sopenharmony_ci		tx_xdp = req_rx_rings;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci	rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp);
93962306a36Sopenharmony_ci	if (rc) {
94062306a36Sopenharmony_ci		netdev_warn(dev, "Unable to allocate the requested rings\n");
94162306a36Sopenharmony_ci		return rc;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=
94562306a36Sopenharmony_ci	    bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) &&
94662306a36Sopenharmony_ci	    netif_is_rxfh_configured(dev)) {
94762306a36Sopenharmony_ci		netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n");
94862306a36Sopenharmony_ci		return -EINVAL;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (netif_running(dev)) {
95262306a36Sopenharmony_ci		if (BNXT_PF(bp)) {
95362306a36Sopenharmony_ci			/* TODO CHIMP_FW: Send message to all VF's
95462306a36Sopenharmony_ci			 * before PF unload
95562306a36Sopenharmony_ci			 */
95662306a36Sopenharmony_ci		}
95762306a36Sopenharmony_ci		bnxt_close_nic(bp, true, false);
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (sh) {
96162306a36Sopenharmony_ci		bp->flags |= BNXT_FLAG_SHARED_RINGS;
96262306a36Sopenharmony_ci		bp->rx_nr_rings = channel->combined_count;
96362306a36Sopenharmony_ci		bp->tx_nr_rings_per_tc = channel->combined_count;
96462306a36Sopenharmony_ci	} else {
96562306a36Sopenharmony_ci		bp->flags &= ~BNXT_FLAG_SHARED_RINGS;
96662306a36Sopenharmony_ci		bp->rx_nr_rings = channel->rx_count;
96762306a36Sopenharmony_ci		bp->tx_nr_rings_per_tc = channel->tx_count;
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci	bp->tx_nr_rings_xdp = tx_xdp;
97062306a36Sopenharmony_ci	bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp;
97162306a36Sopenharmony_ci	if (tcs > 1)
97262306a36Sopenharmony_ci		bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
97562306a36Sopenharmony_ci			       bp->tx_nr_rings + bp->rx_nr_rings;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* After changing number of rx channels, update NTUPLE feature. */
97862306a36Sopenharmony_ci	netdev_update_features(dev);
97962306a36Sopenharmony_ci	if (netif_running(dev)) {
98062306a36Sopenharmony_ci		rc = bnxt_open_nic(bp, true, false);
98162306a36Sopenharmony_ci		if ((!rc) && BNXT_PF(bp)) {
98262306a36Sopenharmony_ci			/* TODO CHIMP_FW: Send message to all VF's
98362306a36Sopenharmony_ci			 * to renable
98462306a36Sopenharmony_ci			 */
98562306a36Sopenharmony_ci		}
98662306a36Sopenharmony_ci	} else {
98762306a36Sopenharmony_ci		rc = bnxt_reserve_rings(bp, true);
98862306a36Sopenharmony_ci	}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	return rc;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
99462306a36Sopenharmony_cistatic int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
99562306a36Sopenharmony_ci			    u32 *rule_locs)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	int i, j = 0;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	cmd->data = bp->ntp_fltr_count;
100062306a36Sopenharmony_ci	for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
100162306a36Sopenharmony_ci		struct hlist_head *head;
100262306a36Sopenharmony_ci		struct bnxt_ntuple_filter *fltr;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		head = &bp->ntp_fltr_hash_tbl[i];
100562306a36Sopenharmony_ci		rcu_read_lock();
100662306a36Sopenharmony_ci		hlist_for_each_entry_rcu(fltr, head, hash) {
100762306a36Sopenharmony_ci			if (j == cmd->rule_cnt)
100862306a36Sopenharmony_ci				break;
100962306a36Sopenharmony_ci			rule_locs[j++] = fltr->sw_id;
101062306a36Sopenharmony_ci		}
101162306a36Sopenharmony_ci		rcu_read_unlock();
101262306a36Sopenharmony_ci		if (j == cmd->rule_cnt)
101362306a36Sopenharmony_ci			break;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci	cmd->rule_cnt = j;
101662306a36Sopenharmony_ci	return 0;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fs =
102262306a36Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
102362306a36Sopenharmony_ci	struct bnxt_ntuple_filter *fltr;
102462306a36Sopenharmony_ci	struct flow_keys *fkeys;
102562306a36Sopenharmony_ci	int i, rc = -EINVAL;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
102862306a36Sopenharmony_ci		return rc;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
103162306a36Sopenharmony_ci		struct hlist_head *head;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		head = &bp->ntp_fltr_hash_tbl[i];
103462306a36Sopenharmony_ci		rcu_read_lock();
103562306a36Sopenharmony_ci		hlist_for_each_entry_rcu(fltr, head, hash) {
103662306a36Sopenharmony_ci			if (fltr->sw_id == fs->location)
103762306a36Sopenharmony_ci				goto fltr_found;
103862306a36Sopenharmony_ci		}
103962306a36Sopenharmony_ci		rcu_read_unlock();
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci	return rc;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cifltr_found:
104462306a36Sopenharmony_ci	fkeys = &fltr->fkeys;
104562306a36Sopenharmony_ci	if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
104662306a36Sopenharmony_ci		if (fkeys->basic.ip_proto == IPPROTO_TCP)
104762306a36Sopenharmony_ci			fs->flow_type = TCP_V4_FLOW;
104862306a36Sopenharmony_ci		else if (fkeys->basic.ip_proto == IPPROTO_UDP)
104962306a36Sopenharmony_ci			fs->flow_type = UDP_V4_FLOW;
105062306a36Sopenharmony_ci		else
105162306a36Sopenharmony_ci			goto fltr_err;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
105462306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
105762306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
106062306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
106362306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
106462306a36Sopenharmony_ci	} else {
106562306a36Sopenharmony_ci		int i;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		if (fkeys->basic.ip_proto == IPPROTO_TCP)
106862306a36Sopenharmony_ci			fs->flow_type = TCP_V6_FLOW;
106962306a36Sopenharmony_ci		else if (fkeys->basic.ip_proto == IPPROTO_UDP)
107062306a36Sopenharmony_ci			fs->flow_type = UDP_V6_FLOW;
107162306a36Sopenharmony_ci		else
107262306a36Sopenharmony_ci			goto fltr_err;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci		*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
107562306a36Sopenharmony_ci			fkeys->addrs.v6addrs.src;
107662306a36Sopenharmony_ci		*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
107762306a36Sopenharmony_ci			fkeys->addrs.v6addrs.dst;
107862306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
107962306a36Sopenharmony_ci			fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0);
108062306a36Sopenharmony_ci			fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0);
108162306a36Sopenharmony_ci		}
108262306a36Sopenharmony_ci		fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
108362306a36Sopenharmony_ci		fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
108662306a36Sopenharmony_ci		fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0);
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	fs->ring_cookie = fltr->rxq;
109062306a36Sopenharmony_ci	rc = 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cifltr_err:
109362306a36Sopenharmony_ci	rcu_read_unlock();
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	return rc;
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci#endif
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic u64 get_ethtool_ipv4_rss(struct bnxt *bp)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
110262306a36Sopenharmony_ci		return RXH_IP_SRC | RXH_IP_DST;
110362306a36Sopenharmony_ci	return 0;
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic u64 get_ethtool_ipv6_rss(struct bnxt *bp)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
110962306a36Sopenharmony_ci		return RXH_IP_SRC | RXH_IP_DST;
111062306a36Sopenharmony_ci	return 0;
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	cmd->data = 0;
111662306a36Sopenharmony_ci	switch (cmd->flow_type) {
111762306a36Sopenharmony_ci	case TCP_V4_FLOW:
111862306a36Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4)
111962306a36Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
112062306a36Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
112162306a36Sopenharmony_ci		cmd->data |= get_ethtool_ipv4_rss(bp);
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	case UDP_V4_FLOW:
112462306a36Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
112562306a36Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
112662306a36Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
112762306a36Sopenharmony_ci		fallthrough;
112862306a36Sopenharmony_ci	case SCTP_V4_FLOW:
112962306a36Sopenharmony_ci	case AH_ESP_V4_FLOW:
113062306a36Sopenharmony_ci	case AH_V4_FLOW:
113162306a36Sopenharmony_ci	case ESP_V4_FLOW:
113262306a36Sopenharmony_ci	case IPV4_FLOW:
113362306a36Sopenharmony_ci		cmd->data |= get_ethtool_ipv4_rss(bp);
113462306a36Sopenharmony_ci		break;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	case TCP_V6_FLOW:
113762306a36Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6)
113862306a36Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
113962306a36Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
114062306a36Sopenharmony_ci		cmd->data |= get_ethtool_ipv6_rss(bp);
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	case UDP_V6_FLOW:
114362306a36Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
114462306a36Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
114562306a36Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
114662306a36Sopenharmony_ci		fallthrough;
114762306a36Sopenharmony_ci	case SCTP_V6_FLOW:
114862306a36Sopenharmony_ci	case AH_ESP_V6_FLOW:
114962306a36Sopenharmony_ci	case AH_V6_FLOW:
115062306a36Sopenharmony_ci	case ESP_V6_FLOW:
115162306a36Sopenharmony_ci	case IPV6_FLOW:
115262306a36Sopenharmony_ci		cmd->data |= get_ethtool_ipv6_rss(bp);
115362306a36Sopenharmony_ci		break;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci	return 0;
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
115962306a36Sopenharmony_ci#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST)
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	u32 rss_hash_cfg = bp->rss_hash_cfg;
116462306a36Sopenharmony_ci	int tuple, rc = 0;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	if (cmd->data == RXH_4TUPLE)
116762306a36Sopenharmony_ci		tuple = 4;
116862306a36Sopenharmony_ci	else if (cmd->data == RXH_2TUPLE)
116962306a36Sopenharmony_ci		tuple = 2;
117062306a36Sopenharmony_ci	else if (!cmd->data)
117162306a36Sopenharmony_ci		tuple = 0;
117262306a36Sopenharmony_ci	else
117362306a36Sopenharmony_ci		return -EINVAL;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	if (cmd->flow_type == TCP_V4_FLOW) {
117662306a36Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
117762306a36Sopenharmony_ci		if (tuple == 4)
117862306a36Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
117962306a36Sopenharmony_ci	} else if (cmd->flow_type == UDP_V4_FLOW) {
118062306a36Sopenharmony_ci		if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
118162306a36Sopenharmony_ci			return -EINVAL;
118262306a36Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
118362306a36Sopenharmony_ci		if (tuple == 4)
118462306a36Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
118562306a36Sopenharmony_ci	} else if (cmd->flow_type == TCP_V6_FLOW) {
118662306a36Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
118762306a36Sopenharmony_ci		if (tuple == 4)
118862306a36Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
118962306a36Sopenharmony_ci	} else if (cmd->flow_type == UDP_V6_FLOW) {
119062306a36Sopenharmony_ci		if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
119162306a36Sopenharmony_ci			return -EINVAL;
119262306a36Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
119362306a36Sopenharmony_ci		if (tuple == 4)
119462306a36Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
119562306a36Sopenharmony_ci	} else if (tuple == 4) {
119662306a36Sopenharmony_ci		return -EINVAL;
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	switch (cmd->flow_type) {
120062306a36Sopenharmony_ci	case TCP_V4_FLOW:
120162306a36Sopenharmony_ci	case UDP_V4_FLOW:
120262306a36Sopenharmony_ci	case SCTP_V4_FLOW:
120362306a36Sopenharmony_ci	case AH_ESP_V4_FLOW:
120462306a36Sopenharmony_ci	case AH_V4_FLOW:
120562306a36Sopenharmony_ci	case ESP_V4_FLOW:
120662306a36Sopenharmony_ci	case IPV4_FLOW:
120762306a36Sopenharmony_ci		if (tuple == 2)
120862306a36Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
120962306a36Sopenharmony_ci		else if (!tuple)
121062306a36Sopenharmony_ci			rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
121162306a36Sopenharmony_ci		break;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	case TCP_V6_FLOW:
121462306a36Sopenharmony_ci	case UDP_V6_FLOW:
121562306a36Sopenharmony_ci	case SCTP_V6_FLOW:
121662306a36Sopenharmony_ci	case AH_ESP_V6_FLOW:
121762306a36Sopenharmony_ci	case AH_V6_FLOW:
121862306a36Sopenharmony_ci	case ESP_V6_FLOW:
121962306a36Sopenharmony_ci	case IPV6_FLOW:
122062306a36Sopenharmony_ci		if (tuple == 2)
122162306a36Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
122262306a36Sopenharmony_ci		else if (!tuple)
122362306a36Sopenharmony_ci			rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
122462306a36Sopenharmony_ci		break;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	if (bp->rss_hash_cfg == rss_hash_cfg)
122862306a36Sopenharmony_ci		return 0;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA)
123162306a36Sopenharmony_ci		bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg;
123262306a36Sopenharmony_ci	bp->rss_hash_cfg = rss_hash_cfg;
123362306a36Sopenharmony_ci	if (netif_running(bp->dev)) {
123462306a36Sopenharmony_ci		bnxt_close_nic(bp, false, false);
123562306a36Sopenharmony_ci		rc = bnxt_open_nic(bp, false, false);
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci	return rc;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
124162306a36Sopenharmony_ci			  u32 *rule_locs)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
124462306a36Sopenharmony_ci	int rc = 0;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	switch (cmd->cmd) {
124762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
124862306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
124962306a36Sopenharmony_ci		cmd->data = bp->rx_nr_rings;
125062306a36Sopenharmony_ci		break;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
125362306a36Sopenharmony_ci		cmd->rule_cnt = bp->ntp_fltr_count;
125462306a36Sopenharmony_ci		cmd->data = BNXT_NTP_FLTR_MAX_FLTR;
125562306a36Sopenharmony_ci		break;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
125862306a36Sopenharmony_ci		rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs);
125962306a36Sopenharmony_ci		break;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
126262306a36Sopenharmony_ci		rc = bnxt_grxclsrule(bp, cmd);
126362306a36Sopenharmony_ci		break;
126462306a36Sopenharmony_ci#endif
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	case ETHTOOL_GRXFH:
126762306a36Sopenharmony_ci		rc = bnxt_grxfh(bp, cmd);
126862306a36Sopenharmony_ci		break;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	default:
127162306a36Sopenharmony_ci		rc = -EOPNOTSUPP;
127262306a36Sopenharmony_ci		break;
127362306a36Sopenharmony_ci	}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return rc;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
128162306a36Sopenharmony_ci	int rc;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	switch (cmd->cmd) {
128462306a36Sopenharmony_ci	case ETHTOOL_SRXFH:
128562306a36Sopenharmony_ci		rc = bnxt_srxfh(bp, cmd);
128662306a36Sopenharmony_ci		break;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	default:
128962306a36Sopenharmony_ci		rc = -EOPNOTSUPP;
129062306a36Sopenharmony_ci		break;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci	return rc;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ciu32 bnxt_get_rxfh_indir_size(struct net_device *dev)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_CHIP_P5)
130062306a36Sopenharmony_ci		return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5);
130162306a36Sopenharmony_ci	return HW_HASH_INDEX_SIZE;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_cistatic u32 bnxt_get_rxfh_key_size(struct net_device *dev)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	return HW_HASH_KEY_SIZE;
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cistatic int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
131062306a36Sopenharmony_ci			 u8 *hfunc)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
131362306a36Sopenharmony_ci	struct bnxt_vnic_info *vnic;
131462306a36Sopenharmony_ci	u32 i, tbl_size;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (hfunc)
131762306a36Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	if (!bp->vnic_info)
132062306a36Sopenharmony_ci		return 0;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	vnic = &bp->vnic_info[0];
132362306a36Sopenharmony_ci	if (indir && bp->rss_indir_tbl) {
132462306a36Sopenharmony_ci		tbl_size = bnxt_get_rxfh_indir_size(dev);
132562306a36Sopenharmony_ci		for (i = 0; i < tbl_size; i++)
132662306a36Sopenharmony_ci			indir[i] = bp->rss_indir_tbl[i];
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (key && vnic->rss_hash_key)
133062306a36Sopenharmony_ci		memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	return 0;
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic int bnxt_set_rxfh(struct net_device *dev, const u32 *indir,
133662306a36Sopenharmony_ci			 const u8 *key, const u8 hfunc)
133762306a36Sopenharmony_ci{
133862306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
133962306a36Sopenharmony_ci	int rc = 0;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	if (hfunc && hfunc != ETH_RSS_HASH_TOP)
134262306a36Sopenharmony_ci		return -EOPNOTSUPP;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (key)
134562306a36Sopenharmony_ci		return -EOPNOTSUPP;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (indir) {
134862306a36Sopenharmony_ci		u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		for (i = 0; i < tbl_size; i++)
135162306a36Sopenharmony_ci			bp->rss_indir_tbl[i] = indir[i];
135262306a36Sopenharmony_ci		pad = bp->rss_indir_tbl_entries - tbl_size;
135362306a36Sopenharmony_ci		if (pad)
135462306a36Sopenharmony_ci			memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16));
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	if (netif_running(bp->dev)) {
135862306a36Sopenharmony_ci		bnxt_close_nic(bp, false, false);
135962306a36Sopenharmony_ci		rc = bnxt_open_nic(bp, false, false);
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci	return rc;
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistatic void bnxt_get_drvinfo(struct net_device *dev,
136562306a36Sopenharmony_ci			     struct ethtool_drvinfo *info)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
137062306a36Sopenharmony_ci	strscpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version));
137162306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
137262306a36Sopenharmony_ci	info->n_stats = bnxt_get_num_stats(bp);
137362306a36Sopenharmony_ci	info->testinfo_len = bp->num_tests;
137462306a36Sopenharmony_ci	/* TODO CHIMP_FW: eeprom dump details */
137562306a36Sopenharmony_ci	info->eedump_len = 0;
137662306a36Sopenharmony_ci	/* TODO CHIMP FW: reg dump details */
137762306a36Sopenharmony_ci	info->regdump_len = 0;
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistatic int bnxt_get_regs_len(struct net_device *dev)
138162306a36Sopenharmony_ci{
138262306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
138362306a36Sopenharmony_ci	int reg_len;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (!BNXT_PF(bp))
138662306a36Sopenharmony_ci		return -EOPNOTSUPP;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	reg_len = BNXT_PXP_REG_LEN;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)
139162306a36Sopenharmony_ci		reg_len += sizeof(struct pcie_ctx_hw_stats);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	return reg_len;
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs,
139762306a36Sopenharmony_ci			  void *_p)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	struct pcie_ctx_hw_stats *hw_pcie_stats;
140062306a36Sopenharmony_ci	struct hwrm_pcie_qstats_input *req;
140162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
140262306a36Sopenharmony_ci	dma_addr_t hw_pcie_stats_addr;
140362306a36Sopenharmony_ci	int rc;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	regs->version = 0;
140662306a36Sopenharmony_ci	bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED))
140962306a36Sopenharmony_ci		return;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	if (hwrm_req_init(bp, req, HWRM_PCIE_QSTATS))
141262306a36Sopenharmony_ci		return;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	hw_pcie_stats = hwrm_req_dma_slice(bp, req, sizeof(*hw_pcie_stats),
141562306a36Sopenharmony_ci					   &hw_pcie_stats_addr);
141662306a36Sopenharmony_ci	if (!hw_pcie_stats) {
141762306a36Sopenharmony_ci		hwrm_req_drop(bp, req);
141862306a36Sopenharmony_ci		return;
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	regs->version = 1;
142262306a36Sopenharmony_ci	hwrm_req_hold(bp, req); /* hold on to slice */
142362306a36Sopenharmony_ci	req->pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats));
142462306a36Sopenharmony_ci	req->pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr);
142562306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
142662306a36Sopenharmony_ci	if (!rc) {
142762306a36Sopenharmony_ci		__le64 *src = (__le64 *)hw_pcie_stats;
142862306a36Sopenharmony_ci		u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN);
142962306a36Sopenharmony_ci		int i;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci		for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++)
143262306a36Sopenharmony_ci			dst[i] = le64_to_cpu(src[i]);
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
143562306a36Sopenharmony_ci}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	wol->supported = 0;
144262306a36Sopenharmony_ci	wol->wolopts = 0;
144362306a36Sopenharmony_ci	memset(&wol->sopass, 0, sizeof(wol->sopass));
144462306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_WOL_CAP) {
144562306a36Sopenharmony_ci		wol->supported = WAKE_MAGIC;
144662306a36Sopenharmony_ci		if (bp->wol)
144762306a36Sopenharmony_ci			wol->wolopts = WAKE_MAGIC;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_cistatic int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (wol->wolopts & ~WAKE_MAGIC)
145662306a36Sopenharmony_ci		return -EINVAL;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC) {
145962306a36Sopenharmony_ci		if (!(bp->flags & BNXT_FLAG_WOL_CAP))
146062306a36Sopenharmony_ci			return -EINVAL;
146162306a36Sopenharmony_ci		if (!bp->wol) {
146262306a36Sopenharmony_ci			if (bnxt_hwrm_alloc_wol_fltr(bp))
146362306a36Sopenharmony_ci				return -EBUSY;
146462306a36Sopenharmony_ci			bp->wol = 1;
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci	} else {
146762306a36Sopenharmony_ci		if (bp->wol) {
146862306a36Sopenharmony_ci			if (bnxt_hwrm_free_wol_fltr(bp))
146962306a36Sopenharmony_ci				return -EBUSY;
147062306a36Sopenharmony_ci			bp->wol = 0;
147162306a36Sopenharmony_ci		}
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ciu32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	u32 speed_mask = 0;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	/* TODO: support 25GB, 40GB, 50GB with different cable type */
148162306a36Sopenharmony_ci	/* set the advertised speeds */
148262306a36Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
148362306a36Sopenharmony_ci		speed_mask |= ADVERTISED_100baseT_Full;
148462306a36Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
148562306a36Sopenharmony_ci		speed_mask |= ADVERTISED_1000baseT_Full;
148662306a36Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
148762306a36Sopenharmony_ci		speed_mask |= ADVERTISED_2500baseX_Full;
148862306a36Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
148962306a36Sopenharmony_ci		speed_mask |= ADVERTISED_10000baseT_Full;
149062306a36Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
149162306a36Sopenharmony_ci		speed_mask |= ADVERTISED_40000baseCR4_Full;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH)
149462306a36Sopenharmony_ci		speed_mask |= ADVERTISED_Pause;
149562306a36Sopenharmony_ci	else if (fw_pause & BNXT_LINK_PAUSE_TX)
149662306a36Sopenharmony_ci		speed_mask |= ADVERTISED_Asym_Pause;
149762306a36Sopenharmony_ci	else if (fw_pause & BNXT_LINK_PAUSE_RX)
149862306a36Sopenharmony_ci		speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	return speed_mask;
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\
150462306a36Sopenharmony_ci{									\
150562306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB)			\
150662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
150762306a36Sopenharmony_ci						     100baseT_Full);	\
150862306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB)			\
150962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
151062306a36Sopenharmony_ci						     1000baseT_Full);	\
151162306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB)			\
151262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
151362306a36Sopenharmony_ci						     10000baseT_Full);	\
151462306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB)			\
151562306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
151662306a36Sopenharmony_ci						     25000baseCR_Full);	\
151762306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB)			\
151862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
151962306a36Sopenharmony_ci						     40000baseCR4_Full);\
152062306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB)			\
152162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
152262306a36Sopenharmony_ci						     50000baseCR2_Full);\
152362306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB)			\
152462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
152562306a36Sopenharmony_ci						     100000baseCR4_Full);\
152662306a36Sopenharmony_ci	if ((fw_pause) & BNXT_LINK_PAUSE_RX) {				\
152762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
152862306a36Sopenharmony_ci						     Pause);		\
152962306a36Sopenharmony_ci		if (!((fw_pause) & BNXT_LINK_PAUSE_TX))			\
153062306a36Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(		\
153162306a36Sopenharmony_ci					lk_ksettings, name, Asym_Pause);\
153262306a36Sopenharmony_ci	} else if ((fw_pause) & BNXT_LINK_PAUSE_TX) {			\
153362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
153462306a36Sopenharmony_ci						     Asym_Pause);	\
153562306a36Sopenharmony_ci	}								\
153662306a36Sopenharmony_ci}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name)		\
153962306a36Sopenharmony_ci{									\
154062306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
154162306a36Sopenharmony_ci						  100baseT_Full) ||	\
154262306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
154362306a36Sopenharmony_ci						  100baseT_Half))	\
154462306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB;		\
154562306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
154662306a36Sopenharmony_ci						  1000baseT_Full) ||	\
154762306a36Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
154862306a36Sopenharmony_ci						  1000baseT_Half))	\
154962306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB;			\
155062306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
155162306a36Sopenharmony_ci						  10000baseT_Full))	\
155262306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB;		\
155362306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
155462306a36Sopenharmony_ci						  25000baseCR_Full))	\
155562306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB;		\
155662306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
155762306a36Sopenharmony_ci						  40000baseCR4_Full))	\
155862306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB;		\
155962306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
156062306a36Sopenharmony_ci						  50000baseCR2_Full))	\
156162306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB;		\
156262306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
156362306a36Sopenharmony_ci						  100000baseCR4_Full))	\
156462306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB;		\
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name)	\
156862306a36Sopenharmony_ci{									\
156962306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB)		\
157062306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
157162306a36Sopenharmony_ci						     50000baseCR_Full);	\
157262306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB)		\
157362306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
157462306a36Sopenharmony_ci						     100000baseCR2_Full);\
157562306a36Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB)		\
157662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
157762306a36Sopenharmony_ci						     200000baseCR4_Full);\
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name)	\
158162306a36Sopenharmony_ci{									\
158262306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
158362306a36Sopenharmony_ci						  50000baseCR_Full))	\
158462306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB;		\
158562306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
158662306a36Sopenharmony_ci						  100000baseCR2_Full))	\
158762306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB;		\
158862306a36Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
158962306a36Sopenharmony_ci						  200000baseCR4_Full))	\
159062306a36Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB;		\
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info,
159462306a36Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
159562306a36Sopenharmony_ci{
159662306a36Sopenharmony_ci	u16 fec_cfg = link_info->fec_cfg;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) {
159962306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
160062306a36Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
160162306a36Sopenharmony_ci		return;
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_BASE_R)
160462306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
160562306a36Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
160662306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_RS)
160762306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
160862306a36Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
160962306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_LLRS)
161062306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
161162306a36Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info,
161562306a36Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	u16 fw_speeds = link_info->advertising;
161862306a36Sopenharmony_ci	u8 fw_pause = 0;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
162162306a36Sopenharmony_ci		fw_pause = link_info->auto_pause_setting;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising);
162462306a36Sopenharmony_ci	fw_speeds = link_info->advertising_pam4;
162562306a36Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising);
162662306a36Sopenharmony_ci	bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings);
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info,
163062306a36Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	u16 fw_speeds = link_info->lp_auto_link_speeds;
163362306a36Sopenharmony_ci	u8 fw_pause = 0;
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
163662306a36Sopenharmony_ci		fw_pause = link_info->lp_pause;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings,
163962306a36Sopenharmony_ci				lp_advertising);
164062306a36Sopenharmony_ci	fw_speeds = link_info->lp_auto_pam4_link_speeds;
164162306a36Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising);
164262306a36Sopenharmony_ci}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info,
164562306a36Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	u16 fec_cfg = link_info->fec_cfg;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_NONE) {
165062306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
165162306a36Sopenharmony_ci				 lk_ksettings->link_modes.supported);
165262306a36Sopenharmony_ci		return;
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP)
165562306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
165662306a36Sopenharmony_ci				 lk_ksettings->link_modes.supported);
165762306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_RS_CAP)
165862306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
165962306a36Sopenharmony_ci				 lk_ksettings->link_modes.supported);
166062306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP)
166162306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
166262306a36Sopenharmony_ci				 lk_ksettings->link_modes.supported);
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info,
166662306a36Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
166962306a36Sopenharmony_ci	u16 fw_speeds = link_info->support_speeds;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported);
167262306a36Sopenharmony_ci	fw_speeds = link_info->support_pam4_speeds;
167362306a36Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE)) {
167662306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
167762306a36Sopenharmony_ci						     Pause);
167862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
167962306a36Sopenharmony_ci						     Asym_Pause);
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	if (link_info->support_auto_speeds ||
168362306a36Sopenharmony_ci	    link_info->support_pam4_auto_speeds)
168462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
168562306a36Sopenharmony_ci						     Autoneg);
168662306a36Sopenharmony_ci	bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings);
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ciu32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
169062306a36Sopenharmony_ci{
169162306a36Sopenharmony_ci	switch (fw_link_speed) {
169262306a36Sopenharmony_ci	case BNXT_LINK_SPEED_100MB:
169362306a36Sopenharmony_ci		return SPEED_100;
169462306a36Sopenharmony_ci	case BNXT_LINK_SPEED_1GB:
169562306a36Sopenharmony_ci		return SPEED_1000;
169662306a36Sopenharmony_ci	case BNXT_LINK_SPEED_2_5GB:
169762306a36Sopenharmony_ci		return SPEED_2500;
169862306a36Sopenharmony_ci	case BNXT_LINK_SPEED_10GB:
169962306a36Sopenharmony_ci		return SPEED_10000;
170062306a36Sopenharmony_ci	case BNXT_LINK_SPEED_20GB:
170162306a36Sopenharmony_ci		return SPEED_20000;
170262306a36Sopenharmony_ci	case BNXT_LINK_SPEED_25GB:
170362306a36Sopenharmony_ci		return SPEED_25000;
170462306a36Sopenharmony_ci	case BNXT_LINK_SPEED_40GB:
170562306a36Sopenharmony_ci		return SPEED_40000;
170662306a36Sopenharmony_ci	case BNXT_LINK_SPEED_50GB:
170762306a36Sopenharmony_ci		return SPEED_50000;
170862306a36Sopenharmony_ci	case BNXT_LINK_SPEED_100GB:
170962306a36Sopenharmony_ci		return SPEED_100000;
171062306a36Sopenharmony_ci	case BNXT_LINK_SPEED_200GB:
171162306a36Sopenharmony_ci		return SPEED_200000;
171262306a36Sopenharmony_ci	default:
171362306a36Sopenharmony_ci		return SPEED_UNKNOWN;
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_cistatic int bnxt_get_link_ksettings(struct net_device *dev,
171862306a36Sopenharmony_ci				   struct ethtool_link_ksettings *lk_ksettings)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
172162306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
172262306a36Sopenharmony_ci	struct ethtool_link_settings *base = &lk_ksettings->base;
172362306a36Sopenharmony_ci	u32 ethtool_speed;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported);
172662306a36Sopenharmony_ci	mutex_lock(&bp->link_lock);
172762306a36Sopenharmony_ci	bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising);
173062306a36Sopenharmony_ci	if (link_info->autoneg) {
173162306a36Sopenharmony_ci		bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings);
173262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings,
173362306a36Sopenharmony_ci						     advertising, Autoneg);
173462306a36Sopenharmony_ci		base->autoneg = AUTONEG_ENABLE;
173562306a36Sopenharmony_ci		base->duplex = DUPLEX_UNKNOWN;
173662306a36Sopenharmony_ci		if (link_info->phy_link_status == BNXT_LINK_LINK) {
173762306a36Sopenharmony_ci			bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings);
173862306a36Sopenharmony_ci			if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
173962306a36Sopenharmony_ci				base->duplex = DUPLEX_FULL;
174062306a36Sopenharmony_ci			else
174162306a36Sopenharmony_ci				base->duplex = DUPLEX_HALF;
174262306a36Sopenharmony_ci		}
174362306a36Sopenharmony_ci		ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
174462306a36Sopenharmony_ci	} else {
174562306a36Sopenharmony_ci		base->autoneg = AUTONEG_DISABLE;
174662306a36Sopenharmony_ci		ethtool_speed =
174762306a36Sopenharmony_ci			bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
174862306a36Sopenharmony_ci		base->duplex = DUPLEX_HALF;
174962306a36Sopenharmony_ci		if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL)
175062306a36Sopenharmony_ci			base->duplex = DUPLEX_FULL;
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci	base->speed = ethtool_speed;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	base->port = PORT_NONE;
175562306a36Sopenharmony_ci	if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
175662306a36Sopenharmony_ci		base->port = PORT_TP;
175762306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
175862306a36Sopenharmony_ci						     TP);
175962306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
176062306a36Sopenharmony_ci						     TP);
176162306a36Sopenharmony_ci	} else {
176262306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
176362306a36Sopenharmony_ci						     FIBRE);
176462306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
176562306a36Sopenharmony_ci						     FIBRE);
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci		if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
176862306a36Sopenharmony_ci			base->port = PORT_DA;
176962306a36Sopenharmony_ci		else if (link_info->media_type ==
177062306a36Sopenharmony_ci			 PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
177162306a36Sopenharmony_ci			base->port = PORT_FIBRE;
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci	base->phy_address = link_info->phy_addr;
177462306a36Sopenharmony_ci	mutex_unlock(&bp->link_lock);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	return 0;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_cistatic int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
178262306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
178362306a36Sopenharmony_ci	u16 support_pam4_spds = link_info->support_pam4_speeds;
178462306a36Sopenharmony_ci	u16 support_spds = link_info->support_speeds;
178562306a36Sopenharmony_ci	u8 sig_mode = BNXT_SIG_MODE_NRZ;
178662306a36Sopenharmony_ci	u16 fw_speed = 0;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	switch (ethtool_speed) {
178962306a36Sopenharmony_ci	case SPEED_100:
179062306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_100MB)
179162306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB;
179262306a36Sopenharmony_ci		break;
179362306a36Sopenharmony_ci	case SPEED_1000:
179462306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_1GB)
179562306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
179662306a36Sopenharmony_ci		break;
179762306a36Sopenharmony_ci	case SPEED_2500:
179862306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB)
179962306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB;
180062306a36Sopenharmony_ci		break;
180162306a36Sopenharmony_ci	case SPEED_10000:
180262306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_10GB)
180362306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
180462306a36Sopenharmony_ci		break;
180562306a36Sopenharmony_ci	case SPEED_20000:
180662306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_20GB)
180762306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB;
180862306a36Sopenharmony_ci		break;
180962306a36Sopenharmony_ci	case SPEED_25000:
181062306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_25GB)
181162306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
181262306a36Sopenharmony_ci		break;
181362306a36Sopenharmony_ci	case SPEED_40000:
181462306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_40GB)
181562306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
181662306a36Sopenharmony_ci		break;
181762306a36Sopenharmony_ci	case SPEED_50000:
181862306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_50GB) {
181962306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
182062306a36Sopenharmony_ci		} else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) {
182162306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB;
182262306a36Sopenharmony_ci			sig_mode = BNXT_SIG_MODE_PAM4;
182362306a36Sopenharmony_ci		}
182462306a36Sopenharmony_ci		break;
182562306a36Sopenharmony_ci	case SPEED_100000:
182662306a36Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_100GB) {
182762306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB;
182862306a36Sopenharmony_ci		} else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) {
182962306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB;
183062306a36Sopenharmony_ci			sig_mode = BNXT_SIG_MODE_PAM4;
183162306a36Sopenharmony_ci		}
183262306a36Sopenharmony_ci		break;
183362306a36Sopenharmony_ci	case SPEED_200000:
183462306a36Sopenharmony_ci		if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) {
183562306a36Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB;
183662306a36Sopenharmony_ci			sig_mode = BNXT_SIG_MODE_PAM4;
183762306a36Sopenharmony_ci		}
183862306a36Sopenharmony_ci		break;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	if (!fw_speed) {
184262306a36Sopenharmony_ci		netdev_err(dev, "unsupported speed!\n");
184362306a36Sopenharmony_ci		return -EINVAL;
184462306a36Sopenharmony_ci	}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	if (link_info->req_link_speed == fw_speed &&
184762306a36Sopenharmony_ci	    link_info->req_signal_mode == sig_mode &&
184862306a36Sopenharmony_ci	    link_info->autoneg == 0)
184962306a36Sopenharmony_ci		return -EALREADY;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	link_info->req_link_speed = fw_speed;
185262306a36Sopenharmony_ci	link_info->req_signal_mode = sig_mode;
185362306a36Sopenharmony_ci	link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
185462306a36Sopenharmony_ci	link_info->autoneg = 0;
185562306a36Sopenharmony_ci	link_info->advertising = 0;
185662306a36Sopenharmony_ci	link_info->advertising_pam4 = 0;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	return 0;
185962306a36Sopenharmony_ci}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ciu16 bnxt_get_fw_auto_link_speeds(u32 advertising)
186262306a36Sopenharmony_ci{
186362306a36Sopenharmony_ci	u16 fw_speed_mask = 0;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	/* only support autoneg at speed 100, 1000, and 10000 */
186662306a36Sopenharmony_ci	if (advertising & (ADVERTISED_100baseT_Full |
186762306a36Sopenharmony_ci			   ADVERTISED_100baseT_Half)) {
186862306a36Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci	if (advertising & (ADVERTISED_1000baseT_Full |
187162306a36Sopenharmony_ci			   ADVERTISED_1000baseT_Half)) {
187262306a36Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci	if (advertising & ADVERTISED_10000baseT_Full)
187562306a36Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	if (advertising & ADVERTISED_40000baseCR4_Full)
187862306a36Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	return fw_speed_mask;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic int bnxt_set_link_ksettings(struct net_device *dev,
188462306a36Sopenharmony_ci			   const struct ethtool_link_ksettings *lk_ksettings)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
188762306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
188862306a36Sopenharmony_ci	const struct ethtool_link_settings *base = &lk_ksettings->base;
188962306a36Sopenharmony_ci	bool set_pause = false;
189062306a36Sopenharmony_ci	u32 speed;
189162306a36Sopenharmony_ci	int rc = 0;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
189462306a36Sopenharmony_ci		return -EOPNOTSUPP;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	mutex_lock(&bp->link_lock);
189762306a36Sopenharmony_ci	if (base->autoneg == AUTONEG_ENABLE) {
189862306a36Sopenharmony_ci		link_info->advertising = 0;
189962306a36Sopenharmony_ci		link_info->advertising_pam4 = 0;
190062306a36Sopenharmony_ci		BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings,
190162306a36Sopenharmony_ci					advertising);
190262306a36Sopenharmony_ci		BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4,
190362306a36Sopenharmony_ci					     lk_ksettings, advertising);
190462306a36Sopenharmony_ci		link_info->autoneg |= BNXT_AUTONEG_SPEED;
190562306a36Sopenharmony_ci		if (!link_info->advertising && !link_info->advertising_pam4) {
190662306a36Sopenharmony_ci			link_info->advertising = link_info->support_auto_speeds;
190762306a36Sopenharmony_ci			link_info->advertising_pam4 =
190862306a36Sopenharmony_ci				link_info->support_pam4_auto_speeds;
190962306a36Sopenharmony_ci		}
191062306a36Sopenharmony_ci		/* any change to autoneg will cause link change, therefore the
191162306a36Sopenharmony_ci		 * driver should put back the original pause setting in autoneg
191262306a36Sopenharmony_ci		 */
191362306a36Sopenharmony_ci		if (!(bp->phy_flags & BNXT_PHY_FL_NO_PAUSE))
191462306a36Sopenharmony_ci			set_pause = true;
191562306a36Sopenharmony_ci	} else {
191662306a36Sopenharmony_ci		u8 phy_type = link_info->phy_type;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci		if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET  ||
191962306a36Sopenharmony_ci		    phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE ||
192062306a36Sopenharmony_ci		    link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
192162306a36Sopenharmony_ci			netdev_err(dev, "10GBase-T devices must autoneg\n");
192262306a36Sopenharmony_ci			rc = -EINVAL;
192362306a36Sopenharmony_ci			goto set_setting_exit;
192462306a36Sopenharmony_ci		}
192562306a36Sopenharmony_ci		if (base->duplex == DUPLEX_HALF) {
192662306a36Sopenharmony_ci			netdev_err(dev, "HALF DUPLEX is not supported!\n");
192762306a36Sopenharmony_ci			rc = -EINVAL;
192862306a36Sopenharmony_ci			goto set_setting_exit;
192962306a36Sopenharmony_ci		}
193062306a36Sopenharmony_ci		speed = base->speed;
193162306a36Sopenharmony_ci		rc = bnxt_force_link_speed(dev, speed);
193262306a36Sopenharmony_ci		if (rc) {
193362306a36Sopenharmony_ci			if (rc == -EALREADY)
193462306a36Sopenharmony_ci				rc = 0;
193562306a36Sopenharmony_ci			goto set_setting_exit;
193662306a36Sopenharmony_ci		}
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	if (netif_running(dev))
194062306a36Sopenharmony_ci		rc = bnxt_hwrm_set_link_setting(bp, set_pause, false);
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ciset_setting_exit:
194362306a36Sopenharmony_ci	mutex_unlock(&bp->link_lock);
194462306a36Sopenharmony_ci	return rc;
194562306a36Sopenharmony_ci}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_cistatic int bnxt_get_fecparam(struct net_device *dev,
194862306a36Sopenharmony_ci			     struct ethtool_fecparam *fec)
194962306a36Sopenharmony_ci{
195062306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
195162306a36Sopenharmony_ci	struct bnxt_link_info *link_info;
195262306a36Sopenharmony_ci	u8 active_fec;
195362306a36Sopenharmony_ci	u16 fec_cfg;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	link_info = &bp->link_info;
195662306a36Sopenharmony_ci	fec_cfg = link_info->fec_cfg;
195762306a36Sopenharmony_ci	active_fec = link_info->active_fec_sig_mode &
195862306a36Sopenharmony_ci		     PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK;
195962306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_NONE) {
196062306a36Sopenharmony_ci		fec->fec = ETHTOOL_FEC_NONE;
196162306a36Sopenharmony_ci		fec->active_fec = ETHTOOL_FEC_NONE;
196262306a36Sopenharmony_ci		return 0;
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_AUTONEG)
196562306a36Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_AUTO;
196662306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_BASE_R)
196762306a36Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_BASER;
196862306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_RS)
196962306a36Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_RS;
197062306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_LLRS)
197162306a36Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_LLRS;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	switch (active_fec) {
197462306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE:
197562306a36Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_BASER;
197662306a36Sopenharmony_ci		break;
197762306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE:
197862306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE:
197962306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE:
198062306a36Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_RS;
198162306a36Sopenharmony_ci		break;
198262306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE:
198362306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE:
198462306a36Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_LLRS;
198562306a36Sopenharmony_ci		break;
198662306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE:
198762306a36Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_OFF;
198862306a36Sopenharmony_ci		break;
198962306a36Sopenharmony_ci	}
199062306a36Sopenharmony_ci	return 0;
199162306a36Sopenharmony_ci}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_cistatic void bnxt_get_fec_stats(struct net_device *dev,
199462306a36Sopenharmony_ci			       struct ethtool_fec_stats *fec_stats)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
199762306a36Sopenharmony_ci	u64 *rx;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT))
200062306a36Sopenharmony_ci		return;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	rx = bp->rx_port_stats_ext.sw_stats;
200362306a36Sopenharmony_ci	fec_stats->corrected_bits.total =
200462306a36Sopenharmony_ci		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits));
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (bp->fw_rx_stats_ext_size <= BNXT_RX_STATS_EXT_NUM_LEGACY)
200762306a36Sopenharmony_ci		return;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	fec_stats->corrected_blocks.total =
201062306a36Sopenharmony_ci		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_corrected_blocks));
201162306a36Sopenharmony_ci	fec_stats->uncorrectable_blocks.total =
201262306a36Sopenharmony_ci		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_fec_uncorrectable_blocks));
201362306a36Sopenharmony_ci}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_cistatic u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info,
201662306a36Sopenharmony_ci					 u32 fec)
201762306a36Sopenharmony_ci{
201862306a36Sopenharmony_ci	u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	if (fec & ETHTOOL_FEC_BASER)
202162306a36Sopenharmony_ci		fw_fec |= BNXT_FEC_BASE_R_ON(link_info);
202262306a36Sopenharmony_ci	else if (fec & ETHTOOL_FEC_RS)
202362306a36Sopenharmony_ci		fw_fec |= BNXT_FEC_RS_ON(link_info);
202462306a36Sopenharmony_ci	else if (fec & ETHTOOL_FEC_LLRS)
202562306a36Sopenharmony_ci		fw_fec |= BNXT_FEC_LLRS_ON;
202662306a36Sopenharmony_ci	return fw_fec;
202762306a36Sopenharmony_ci}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic int bnxt_set_fecparam(struct net_device *dev,
203062306a36Sopenharmony_ci			     struct ethtool_fecparam *fecparam)
203162306a36Sopenharmony_ci{
203262306a36Sopenharmony_ci	struct hwrm_port_phy_cfg_input *req;
203362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
203462306a36Sopenharmony_ci	struct bnxt_link_info *link_info;
203562306a36Sopenharmony_ci	u32 new_cfg, fec = fecparam->fec;
203662306a36Sopenharmony_ci	u16 fec_cfg;
203762306a36Sopenharmony_ci	int rc;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	link_info = &bp->link_info;
204062306a36Sopenharmony_ci	fec_cfg = link_info->fec_cfg;
204162306a36Sopenharmony_ci	if (fec_cfg & BNXT_FEC_NONE)
204262306a36Sopenharmony_ci		return -EOPNOTSUPP;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	if (fec & ETHTOOL_FEC_OFF) {
204562306a36Sopenharmony_ci		new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE |
204662306a36Sopenharmony_ci			  BNXT_FEC_ALL_OFF(link_info);
204762306a36Sopenharmony_ci		goto apply_fec;
204862306a36Sopenharmony_ci	}
204962306a36Sopenharmony_ci	if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) ||
205062306a36Sopenharmony_ci	    ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) ||
205162306a36Sopenharmony_ci	    ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) ||
205262306a36Sopenharmony_ci	    ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP)))
205362306a36Sopenharmony_ci		return -EINVAL;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	if (fec & ETHTOOL_FEC_AUTO) {
205662306a36Sopenharmony_ci		if (!link_info->autoneg)
205762306a36Sopenharmony_ci			return -EINVAL;
205862306a36Sopenharmony_ci		new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE;
205962306a36Sopenharmony_ci	} else {
206062306a36Sopenharmony_ci		new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec);
206162306a36Sopenharmony_ci	}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ciapply_fec:
206462306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG);
206562306a36Sopenharmony_ci	if (rc)
206662306a36Sopenharmony_ci		return rc;
206762306a36Sopenharmony_ci	req->flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
206862306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
206962306a36Sopenharmony_ci	/* update current settings */
207062306a36Sopenharmony_ci	if (!rc) {
207162306a36Sopenharmony_ci		mutex_lock(&bp->link_lock);
207262306a36Sopenharmony_ci		bnxt_update_link(bp, false);
207362306a36Sopenharmony_ci		mutex_unlock(&bp->link_lock);
207462306a36Sopenharmony_ci	}
207562306a36Sopenharmony_ci	return rc;
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic void bnxt_get_pauseparam(struct net_device *dev,
207962306a36Sopenharmony_ci				struct ethtool_pauseparam *epause)
208062306a36Sopenharmony_ci{
208162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
208262306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	if (BNXT_VF(bp))
208562306a36Sopenharmony_ci		return;
208662306a36Sopenharmony_ci	epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL);
208762306a36Sopenharmony_ci	epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX);
208862306a36Sopenharmony_ci	epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX);
208962306a36Sopenharmony_ci}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_cistatic void bnxt_get_pause_stats(struct net_device *dev,
209262306a36Sopenharmony_ci				 struct ethtool_pause_stats *epstat)
209362306a36Sopenharmony_ci{
209462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
209562306a36Sopenharmony_ci	u64 *rx, *tx;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
209862306a36Sopenharmony_ci		return;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	rx = bp->port_stats.sw_stats;
210162306a36Sopenharmony_ci	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames);
210462306a36Sopenharmony_ci	epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames);
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_cistatic int bnxt_set_pauseparam(struct net_device *dev,
210862306a36Sopenharmony_ci			       struct ethtool_pauseparam *epause)
210962306a36Sopenharmony_ci{
211062306a36Sopenharmony_ci	int rc = 0;
211162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
211262306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp) || (bp->phy_flags & BNXT_PHY_FL_NO_PAUSE))
211562306a36Sopenharmony_ci		return -EOPNOTSUPP;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	mutex_lock(&bp->link_lock);
211862306a36Sopenharmony_ci	if (epause->autoneg) {
211962306a36Sopenharmony_ci		if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
212062306a36Sopenharmony_ci			rc = -EINVAL;
212162306a36Sopenharmony_ci			goto pause_exit;
212262306a36Sopenharmony_ci		}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci		link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
212562306a36Sopenharmony_ci		link_info->req_flow_ctrl = 0;
212662306a36Sopenharmony_ci	} else {
212762306a36Sopenharmony_ci		/* when transition from auto pause to force pause,
212862306a36Sopenharmony_ci		 * force a link change
212962306a36Sopenharmony_ci		 */
213062306a36Sopenharmony_ci		if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
213162306a36Sopenharmony_ci			link_info->force_link_chng = true;
213262306a36Sopenharmony_ci		link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL;
213362306a36Sopenharmony_ci		link_info->req_flow_ctrl = 0;
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci	if (epause->rx_pause)
213662306a36Sopenharmony_ci		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	if (epause->tx_pause)
213962306a36Sopenharmony_ci		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	if (netif_running(dev))
214262306a36Sopenharmony_ci		rc = bnxt_hwrm_set_pause(bp);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_cipause_exit:
214562306a36Sopenharmony_ci	mutex_unlock(&bp->link_lock);
214662306a36Sopenharmony_ci	return rc;
214762306a36Sopenharmony_ci}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_cistatic u32 bnxt_get_link(struct net_device *dev)
215062306a36Sopenharmony_ci{
215162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	/* TODO: handle MF, VF, driver close case */
215462306a36Sopenharmony_ci	return BNXT_LINK_IS_UP(bp);
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ciint bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp,
215862306a36Sopenharmony_ci			       struct hwrm_nvm_get_dev_info_output *nvm_dev_info)
215962306a36Sopenharmony_ci{
216062306a36Sopenharmony_ci	struct hwrm_nvm_get_dev_info_output *resp;
216162306a36Sopenharmony_ci	struct hwrm_nvm_get_dev_info_input *req;
216262306a36Sopenharmony_ci	int rc;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	if (BNXT_VF(bp))
216562306a36Sopenharmony_ci		return -EOPNOTSUPP;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DEV_INFO);
216862306a36Sopenharmony_ci	if (rc)
216962306a36Sopenharmony_ci		return rc;
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	resp = hwrm_req_hold(bp, req);
217262306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
217362306a36Sopenharmony_ci	if (!rc)
217462306a36Sopenharmony_ci		memcpy(nvm_dev_info, resp, sizeof(*resp));
217562306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
217662306a36Sopenharmony_ci	return rc;
217762306a36Sopenharmony_ci}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_cistatic void bnxt_print_admin_err(struct bnxt *bp)
218062306a36Sopenharmony_ci{
218162306a36Sopenharmony_ci	netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n");
218262306a36Sopenharmony_ci}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ciint bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
218562306a36Sopenharmony_ci			 u16 ext, u16 *index, u32 *item_length,
218662306a36Sopenharmony_ci			 u32 *data_length);
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ciint bnxt_flash_nvram(struct net_device *dev, u16 dir_type,
218962306a36Sopenharmony_ci		     u16 dir_ordinal, u16 dir_ext, u16 dir_attr,
219062306a36Sopenharmony_ci		     u32 dir_item_len, const u8 *data,
219162306a36Sopenharmony_ci		     size_t data_len)
219262306a36Sopenharmony_ci{
219362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
219462306a36Sopenharmony_ci	struct hwrm_nvm_write_input *req;
219562306a36Sopenharmony_ci	int rc;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_WRITE);
219862306a36Sopenharmony_ci	if (rc)
219962306a36Sopenharmony_ci		return rc;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	if (data_len && data) {
220262306a36Sopenharmony_ci		dma_addr_t dma_handle;
220362306a36Sopenharmony_ci		u8 *kmem;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci		kmem = hwrm_req_dma_slice(bp, req, data_len, &dma_handle);
220662306a36Sopenharmony_ci		if (!kmem) {
220762306a36Sopenharmony_ci			hwrm_req_drop(bp, req);
220862306a36Sopenharmony_ci			return -ENOMEM;
220962306a36Sopenharmony_ci		}
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci		req->dir_data_length = cpu_to_le32(data_len);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		memcpy(kmem, data, data_len);
221462306a36Sopenharmony_ci		req->host_src_addr = cpu_to_le64(dma_handle);
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	hwrm_req_timeout(bp, req, bp->hwrm_cmd_max_timeout);
221862306a36Sopenharmony_ci	req->dir_type = cpu_to_le16(dir_type);
221962306a36Sopenharmony_ci	req->dir_ordinal = cpu_to_le16(dir_ordinal);
222062306a36Sopenharmony_ci	req->dir_ext = cpu_to_le16(dir_ext);
222162306a36Sopenharmony_ci	req->dir_attr = cpu_to_le16(dir_attr);
222262306a36Sopenharmony_ci	req->dir_item_length = cpu_to_le32(dir_item_len);
222362306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	if (rc == -EACCES)
222662306a36Sopenharmony_ci		bnxt_print_admin_err(bp);
222762306a36Sopenharmony_ci	return rc;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ciint bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
223162306a36Sopenharmony_ci			     u8 self_reset, u8 flags)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
223462306a36Sopenharmony_ci	struct hwrm_fw_reset_input *req;
223562306a36Sopenharmony_ci	int rc;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	if (!bnxt_hwrm_reset_permitted(bp)) {
223862306a36Sopenharmony_ci		netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver");
223962306a36Sopenharmony_ci		return -EPERM;
224062306a36Sopenharmony_ci	}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_FW_RESET);
224362306a36Sopenharmony_ci	if (rc)
224462306a36Sopenharmony_ci		return rc;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	req->embedded_proc_type = proc_type;
224762306a36Sopenharmony_ci	req->selfrst_status = self_reset;
224862306a36Sopenharmony_ci	req->flags = flags;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) {
225162306a36Sopenharmony_ci		rc = hwrm_req_send_silent(bp, req);
225262306a36Sopenharmony_ci	} else {
225362306a36Sopenharmony_ci		rc = hwrm_req_send(bp, req);
225462306a36Sopenharmony_ci		if (rc == -EACCES)
225562306a36Sopenharmony_ci			bnxt_print_admin_err(bp);
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci	return rc;
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_cistatic int bnxt_firmware_reset(struct net_device *dev,
226162306a36Sopenharmony_ci			       enum bnxt_nvm_directory_type dir_type)
226262306a36Sopenharmony_ci{
226362306a36Sopenharmony_ci	u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE;
226462306a36Sopenharmony_ci	u8 proc_type, flags = 0;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	/* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */
226762306a36Sopenharmony_ci	/*       (e.g. when firmware isn't already running) */
226862306a36Sopenharmony_ci	switch (dir_type) {
226962306a36Sopenharmony_ci	case BNX_DIR_TYPE_CHIMP_PATCH:
227062306a36Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE:
227162306a36Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE_2:
227262306a36Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT;
227362306a36Sopenharmony_ci		/* Self-reset ChiMP upon next PCIe reset: */
227462306a36Sopenharmony_ci		self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
227562306a36Sopenharmony_ci		break;
227662306a36Sopenharmony_ci	case BNX_DIR_TYPE_APE_FW:
227762306a36Sopenharmony_ci	case BNX_DIR_TYPE_APE_PATCH:
227862306a36Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT;
227962306a36Sopenharmony_ci		/* Self-reset APE upon next PCIe reset: */
228062306a36Sopenharmony_ci		self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
228162306a36Sopenharmony_ci		break;
228262306a36Sopenharmony_ci	case BNX_DIR_TYPE_KONG_FW:
228362306a36Sopenharmony_ci	case BNX_DIR_TYPE_KONG_PATCH:
228462306a36Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL;
228562306a36Sopenharmony_ci		break;
228662306a36Sopenharmony_ci	case BNX_DIR_TYPE_BONO_FW:
228762306a36Sopenharmony_ci	case BNX_DIR_TYPE_BONO_PATCH:
228862306a36Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE;
228962306a36Sopenharmony_ci		break;
229062306a36Sopenharmony_ci	default:
229162306a36Sopenharmony_ci		return -EINVAL;
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags);
229562306a36Sopenharmony_ci}
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_cistatic int bnxt_firmware_reset_chip(struct net_device *dev)
229862306a36Sopenharmony_ci{
229962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
230062306a36Sopenharmony_ci	u8 flags = 0;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET)
230362306a36Sopenharmony_ci		flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	return bnxt_hwrm_firmware_reset(dev,
230662306a36Sopenharmony_ci					FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP,
230762306a36Sopenharmony_ci					FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP,
230862306a36Sopenharmony_ci					flags);
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_cistatic int bnxt_firmware_reset_ap(struct net_device *dev)
231262306a36Sopenharmony_ci{
231362306a36Sopenharmony_ci	return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP,
231462306a36Sopenharmony_ci					FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE,
231562306a36Sopenharmony_ci					0);
231662306a36Sopenharmony_ci}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_cistatic int bnxt_flash_firmware(struct net_device *dev,
231962306a36Sopenharmony_ci			       u16 dir_type,
232062306a36Sopenharmony_ci			       const u8 *fw_data,
232162306a36Sopenharmony_ci			       size_t fw_size)
232262306a36Sopenharmony_ci{
232362306a36Sopenharmony_ci	int	rc = 0;
232462306a36Sopenharmony_ci	u16	code_type;
232562306a36Sopenharmony_ci	u32	stored_crc;
232662306a36Sopenharmony_ci	u32	calculated_crc;
232762306a36Sopenharmony_ci	struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	switch (dir_type) {
233062306a36Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE:
233162306a36Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE_2:
233262306a36Sopenharmony_ci		code_type = CODE_BOOT;
233362306a36Sopenharmony_ci		break;
233462306a36Sopenharmony_ci	case BNX_DIR_TYPE_CHIMP_PATCH:
233562306a36Sopenharmony_ci		code_type = CODE_CHIMP_PATCH;
233662306a36Sopenharmony_ci		break;
233762306a36Sopenharmony_ci	case BNX_DIR_TYPE_APE_FW:
233862306a36Sopenharmony_ci		code_type = CODE_MCTP_PASSTHRU;
233962306a36Sopenharmony_ci		break;
234062306a36Sopenharmony_ci	case BNX_DIR_TYPE_APE_PATCH:
234162306a36Sopenharmony_ci		code_type = CODE_APE_PATCH;
234262306a36Sopenharmony_ci		break;
234362306a36Sopenharmony_ci	case BNX_DIR_TYPE_KONG_FW:
234462306a36Sopenharmony_ci		code_type = CODE_KONG_FW;
234562306a36Sopenharmony_ci		break;
234662306a36Sopenharmony_ci	case BNX_DIR_TYPE_KONG_PATCH:
234762306a36Sopenharmony_ci		code_type = CODE_KONG_PATCH;
234862306a36Sopenharmony_ci		break;
234962306a36Sopenharmony_ci	case BNX_DIR_TYPE_BONO_FW:
235062306a36Sopenharmony_ci		code_type = CODE_BONO_FW;
235162306a36Sopenharmony_ci		break;
235262306a36Sopenharmony_ci	case BNX_DIR_TYPE_BONO_PATCH:
235362306a36Sopenharmony_ci		code_type = CODE_BONO_PATCH;
235462306a36Sopenharmony_ci		break;
235562306a36Sopenharmony_ci	default:
235662306a36Sopenharmony_ci		netdev_err(dev, "Unsupported directory entry type: %u\n",
235762306a36Sopenharmony_ci			   dir_type);
235862306a36Sopenharmony_ci		return -EINVAL;
235962306a36Sopenharmony_ci	}
236062306a36Sopenharmony_ci	if (fw_size < sizeof(struct bnxt_fw_header)) {
236162306a36Sopenharmony_ci		netdev_err(dev, "Invalid firmware file size: %u\n",
236262306a36Sopenharmony_ci			   (unsigned int)fw_size);
236362306a36Sopenharmony_ci		return -EINVAL;
236462306a36Sopenharmony_ci	}
236562306a36Sopenharmony_ci	if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) {
236662306a36Sopenharmony_ci		netdev_err(dev, "Invalid firmware signature: %08X\n",
236762306a36Sopenharmony_ci			   le32_to_cpu(header->signature));
236862306a36Sopenharmony_ci		return -EINVAL;
236962306a36Sopenharmony_ci	}
237062306a36Sopenharmony_ci	if (header->code_type != code_type) {
237162306a36Sopenharmony_ci		netdev_err(dev, "Expected firmware type: %d, read: %d\n",
237262306a36Sopenharmony_ci			   code_type, header->code_type);
237362306a36Sopenharmony_ci		return -EINVAL;
237462306a36Sopenharmony_ci	}
237562306a36Sopenharmony_ci	if (header->device != DEVICE_CUMULUS_FAMILY) {
237662306a36Sopenharmony_ci		netdev_err(dev, "Expected firmware device family %d, read: %d\n",
237762306a36Sopenharmony_ci			   DEVICE_CUMULUS_FAMILY, header->device);
237862306a36Sopenharmony_ci		return -EINVAL;
237962306a36Sopenharmony_ci	}
238062306a36Sopenharmony_ci	/* Confirm the CRC32 checksum of the file: */
238162306a36Sopenharmony_ci	stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
238262306a36Sopenharmony_ci					     sizeof(stored_crc)));
238362306a36Sopenharmony_ci	calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
238462306a36Sopenharmony_ci	if (calculated_crc != stored_crc) {
238562306a36Sopenharmony_ci		netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n",
238662306a36Sopenharmony_ci			   (unsigned long)stored_crc,
238762306a36Sopenharmony_ci			   (unsigned long)calculated_crc);
238862306a36Sopenharmony_ci		return -EINVAL;
238962306a36Sopenharmony_ci	}
239062306a36Sopenharmony_ci	rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
239162306a36Sopenharmony_ci			      0, 0, 0, fw_data, fw_size);
239262306a36Sopenharmony_ci	if (rc == 0)	/* Firmware update successful */
239362306a36Sopenharmony_ci		rc = bnxt_firmware_reset(dev, dir_type);
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	return rc;
239662306a36Sopenharmony_ci}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_cistatic int bnxt_flash_microcode(struct net_device *dev,
239962306a36Sopenharmony_ci				u16 dir_type,
240062306a36Sopenharmony_ci				const u8 *fw_data,
240162306a36Sopenharmony_ci				size_t fw_size)
240262306a36Sopenharmony_ci{
240362306a36Sopenharmony_ci	struct bnxt_ucode_trailer *trailer;
240462306a36Sopenharmony_ci	u32 calculated_crc;
240562306a36Sopenharmony_ci	u32 stored_crc;
240662306a36Sopenharmony_ci	int rc = 0;
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	if (fw_size < sizeof(struct bnxt_ucode_trailer)) {
240962306a36Sopenharmony_ci		netdev_err(dev, "Invalid microcode file size: %u\n",
241062306a36Sopenharmony_ci			   (unsigned int)fw_size);
241162306a36Sopenharmony_ci		return -EINVAL;
241262306a36Sopenharmony_ci	}
241362306a36Sopenharmony_ci	trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size -
241462306a36Sopenharmony_ci						sizeof(*trailer)));
241562306a36Sopenharmony_ci	if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) {
241662306a36Sopenharmony_ci		netdev_err(dev, "Invalid microcode trailer signature: %08X\n",
241762306a36Sopenharmony_ci			   le32_to_cpu(trailer->sig));
241862306a36Sopenharmony_ci		return -EINVAL;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ci	if (le16_to_cpu(trailer->dir_type) != dir_type) {
242162306a36Sopenharmony_ci		netdev_err(dev, "Expected microcode type: %d, read: %d\n",
242262306a36Sopenharmony_ci			   dir_type, le16_to_cpu(trailer->dir_type));
242362306a36Sopenharmony_ci		return -EINVAL;
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci	if (le16_to_cpu(trailer->trailer_length) <
242662306a36Sopenharmony_ci		sizeof(struct bnxt_ucode_trailer)) {
242762306a36Sopenharmony_ci		netdev_err(dev, "Invalid microcode trailer length: %d\n",
242862306a36Sopenharmony_ci			   le16_to_cpu(trailer->trailer_length));
242962306a36Sopenharmony_ci		return -EINVAL;
243062306a36Sopenharmony_ci	}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	/* Confirm the CRC32 checksum of the file: */
243362306a36Sopenharmony_ci	stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
243462306a36Sopenharmony_ci					     sizeof(stored_crc)));
243562306a36Sopenharmony_ci	calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
243662306a36Sopenharmony_ci	if (calculated_crc != stored_crc) {
243762306a36Sopenharmony_ci		netdev_err(dev,
243862306a36Sopenharmony_ci			   "CRC32 (%08lX) does not match calculated: %08lX\n",
243962306a36Sopenharmony_ci			   (unsigned long)stored_crc,
244062306a36Sopenharmony_ci			   (unsigned long)calculated_crc);
244162306a36Sopenharmony_ci		return -EINVAL;
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci	rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
244462306a36Sopenharmony_ci			      0, 0, 0, fw_data, fw_size);
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	return rc;
244762306a36Sopenharmony_ci}
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_cistatic bool bnxt_dir_type_is_ape_bin_format(u16 dir_type)
245062306a36Sopenharmony_ci{
245162306a36Sopenharmony_ci	switch (dir_type) {
245262306a36Sopenharmony_ci	case BNX_DIR_TYPE_CHIMP_PATCH:
245362306a36Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE:
245462306a36Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE_2:
245562306a36Sopenharmony_ci	case BNX_DIR_TYPE_APE_FW:
245662306a36Sopenharmony_ci	case BNX_DIR_TYPE_APE_PATCH:
245762306a36Sopenharmony_ci	case BNX_DIR_TYPE_KONG_FW:
245862306a36Sopenharmony_ci	case BNX_DIR_TYPE_KONG_PATCH:
245962306a36Sopenharmony_ci	case BNX_DIR_TYPE_BONO_FW:
246062306a36Sopenharmony_ci	case BNX_DIR_TYPE_BONO_PATCH:
246162306a36Sopenharmony_ci		return true;
246262306a36Sopenharmony_ci	}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	return false;
246562306a36Sopenharmony_ci}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_cistatic bool bnxt_dir_type_is_other_exec_format(u16 dir_type)
246862306a36Sopenharmony_ci{
246962306a36Sopenharmony_ci	switch (dir_type) {
247062306a36Sopenharmony_ci	case BNX_DIR_TYPE_AVS:
247162306a36Sopenharmony_ci	case BNX_DIR_TYPE_EXP_ROM_MBA:
247262306a36Sopenharmony_ci	case BNX_DIR_TYPE_PCIE:
247362306a36Sopenharmony_ci	case BNX_DIR_TYPE_TSCF_UCODE:
247462306a36Sopenharmony_ci	case BNX_DIR_TYPE_EXT_PHY:
247562306a36Sopenharmony_ci	case BNX_DIR_TYPE_CCM:
247662306a36Sopenharmony_ci	case BNX_DIR_TYPE_ISCSI_BOOT:
247762306a36Sopenharmony_ci	case BNX_DIR_TYPE_ISCSI_BOOT_IPV6:
247862306a36Sopenharmony_ci	case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6:
247962306a36Sopenharmony_ci		return true;
248062306a36Sopenharmony_ci	}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	return false;
248362306a36Sopenharmony_ci}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_cistatic bool bnxt_dir_type_is_executable(u16 dir_type)
248662306a36Sopenharmony_ci{
248762306a36Sopenharmony_ci	return bnxt_dir_type_is_ape_bin_format(dir_type) ||
248862306a36Sopenharmony_ci		bnxt_dir_type_is_other_exec_format(dir_type);
248962306a36Sopenharmony_ci}
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_cistatic int bnxt_flash_firmware_from_file(struct net_device *dev,
249262306a36Sopenharmony_ci					 u16 dir_type,
249362306a36Sopenharmony_ci					 const char *filename)
249462306a36Sopenharmony_ci{
249562306a36Sopenharmony_ci	const struct firmware  *fw;
249662306a36Sopenharmony_ci	int			rc;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	rc = request_firmware(&fw, filename, &dev->dev);
249962306a36Sopenharmony_ci	if (rc != 0) {
250062306a36Sopenharmony_ci		netdev_err(dev, "Error %d requesting firmware file: %s\n",
250162306a36Sopenharmony_ci			   rc, filename);
250262306a36Sopenharmony_ci		return rc;
250362306a36Sopenharmony_ci	}
250462306a36Sopenharmony_ci	if (bnxt_dir_type_is_ape_bin_format(dir_type))
250562306a36Sopenharmony_ci		rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size);
250662306a36Sopenharmony_ci	else if (bnxt_dir_type_is_other_exec_format(dir_type))
250762306a36Sopenharmony_ci		rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size);
250862306a36Sopenharmony_ci	else
250962306a36Sopenharmony_ci		rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
251062306a36Sopenharmony_ci				      0, 0, 0, fw->data, fw->size);
251162306a36Sopenharmony_ci	release_firmware(fw);
251262306a36Sopenharmony_ci	return rc;
251362306a36Sopenharmony_ci}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci#define MSG_INTEGRITY_ERR "PKG install error : Data integrity on NVM"
251662306a36Sopenharmony_ci#define MSG_INVALID_PKG "PKG install error : Invalid package"
251762306a36Sopenharmony_ci#define MSG_AUTHENTICATION_ERR "PKG install error : Authentication error"
251862306a36Sopenharmony_ci#define MSG_INVALID_DEV "PKG install error : Invalid device"
251962306a36Sopenharmony_ci#define MSG_INTERNAL_ERR "PKG install error : Internal error"
252062306a36Sopenharmony_ci#define MSG_NO_PKG_UPDATE_AREA_ERR "PKG update area not created in nvram"
252162306a36Sopenharmony_ci#define MSG_NO_SPACE_ERR "PKG insufficient update area in nvram"
252262306a36Sopenharmony_ci#define MSG_RESIZE_UPDATE_ERR "Resize UPDATE entry error"
252362306a36Sopenharmony_ci#define MSG_ANTI_ROLLBACK_ERR "HWRM_NVM_INSTALL_UPDATE failure due to Anti-rollback detected"
252462306a36Sopenharmony_ci#define MSG_GENERIC_FAILURE_ERR "HWRM_NVM_INSTALL_UPDATE failure"
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_cistatic int nvm_update_err_to_stderr(struct net_device *dev, u8 result,
252762306a36Sopenharmony_ci				    struct netlink_ext_ack *extack)
252862306a36Sopenharmony_ci{
252962306a36Sopenharmony_ci	switch (result) {
253062306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TYPE_PARAMETER:
253162306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_INDEX_PARAMETER:
253262306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_DATA_ERROR:
253362306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_CHECKSUM_ERROR:
253462306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_NOT_FOUND:
253562306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_ITEM_LOCKED:
253662306a36Sopenharmony_ci		BNXT_NVM_ERR_MSG(dev, extack, MSG_INTEGRITY_ERR);
253762306a36Sopenharmony_ci		return -EINVAL;
253862306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PREREQUISITE:
253962306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_FILE_HEADER:
254062306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_SIGNATURE:
254162306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_STREAM:
254262306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_PROP_LENGTH:
254362306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_MANIFEST:
254462306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_TRAILER:
254562306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_CHECKSUM:
254662306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_ITEM_CHECKSUM:
254762306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DATA_LENGTH:
254862306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INVALID_DIRECTIVE:
254962306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_DUPLICATE_ITEM:
255062306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_ZERO_LENGTH_ITEM:
255162306a36Sopenharmony_ci		BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_PKG);
255262306a36Sopenharmony_ci		return -ENOPKG;
255362306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_INSTALL_AUTHENTICATION_ERROR:
255462306a36Sopenharmony_ci		BNXT_NVM_ERR_MSG(dev, extack, MSG_AUTHENTICATION_ERR);
255562306a36Sopenharmony_ci		return -EPERM;
255662306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_CHIP_REV:
255762306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_DEVICE_ID:
255862306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_VENDOR:
255962306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_SUBSYS_ID:
256062306a36Sopenharmony_ci	case NVM_INSTALL_UPDATE_RESP_RESULT_UNSUPPORTED_PLATFORM:
256162306a36Sopenharmony_ci		BNXT_NVM_ERR_MSG(dev, extack, MSG_INVALID_DEV);
256262306a36Sopenharmony_ci		return -EOPNOTSUPP;
256362306a36Sopenharmony_ci	default:
256462306a36Sopenharmony_ci		BNXT_NVM_ERR_MSG(dev, extack, MSG_INTERNAL_ERR);
256562306a36Sopenharmony_ci		return -EIO;
256662306a36Sopenharmony_ci	}
256762306a36Sopenharmony_ci}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci#define BNXT_PKG_DMA_SIZE	0x40000
257062306a36Sopenharmony_ci#define BNXT_NVM_MORE_FLAG	(cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_MODE))
257162306a36Sopenharmony_ci#define BNXT_NVM_LAST_FLAG	(cpu_to_le16(NVM_MODIFY_REQ_FLAGS_BATCH_LAST))
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_cistatic int bnxt_resize_update_entry(struct net_device *dev, size_t fw_size,
257462306a36Sopenharmony_ci				    struct netlink_ext_ack *extack)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	u32 item_len;
257762306a36Sopenharmony_ci	int rc;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE,
258062306a36Sopenharmony_ci				  BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, NULL,
258162306a36Sopenharmony_ci				  &item_len, NULL);
258262306a36Sopenharmony_ci	if (rc) {
258362306a36Sopenharmony_ci		BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR);
258462306a36Sopenharmony_ci		return rc;
258562306a36Sopenharmony_ci	}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	if (fw_size > item_len) {
258862306a36Sopenharmony_ci		rc = bnxt_flash_nvram(dev, BNX_DIR_TYPE_UPDATE,
258962306a36Sopenharmony_ci				      BNX_DIR_ORDINAL_FIRST, 0, 1,
259062306a36Sopenharmony_ci				      round_up(fw_size, 4096), NULL, 0);
259162306a36Sopenharmony_ci		if (rc) {
259262306a36Sopenharmony_ci			BNXT_NVM_ERR_MSG(dev, extack, MSG_RESIZE_UPDATE_ERR);
259362306a36Sopenharmony_ci			return rc;
259462306a36Sopenharmony_ci		}
259562306a36Sopenharmony_ci	}
259662306a36Sopenharmony_ci	return 0;
259762306a36Sopenharmony_ci}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ciint bnxt_flash_package_from_fw_obj(struct net_device *dev, const struct firmware *fw,
260062306a36Sopenharmony_ci				   u32 install_type, struct netlink_ext_ack *extack)
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	struct hwrm_nvm_install_update_input *install;
260362306a36Sopenharmony_ci	struct hwrm_nvm_install_update_output *resp;
260462306a36Sopenharmony_ci	struct hwrm_nvm_modify_input *modify;
260562306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
260662306a36Sopenharmony_ci	bool defrag_attempted = false;
260762306a36Sopenharmony_ci	dma_addr_t dma_handle;
260862306a36Sopenharmony_ci	u8 *kmem = NULL;
260962306a36Sopenharmony_ci	u32 modify_len;
261062306a36Sopenharmony_ci	u32 item_len;
261162306a36Sopenharmony_ci	u8 cmd_err;
261262306a36Sopenharmony_ci	u16 index;
261362306a36Sopenharmony_ci	int rc;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	/* resize before flashing larger image than available space */
261662306a36Sopenharmony_ci	rc = bnxt_resize_update_entry(dev, fw->size, extack);
261762306a36Sopenharmony_ci	if (rc)
261862306a36Sopenharmony_ci		return rc;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	bnxt_hwrm_fw_set_time(bp);
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	rc = hwrm_req_init(bp, modify, HWRM_NVM_MODIFY);
262362306a36Sopenharmony_ci	if (rc)
262462306a36Sopenharmony_ci		return rc;
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci	/* Try allocating a large DMA buffer first.  Older fw will
262762306a36Sopenharmony_ci	 * cause excessive NVRAM erases when using small blocks.
262862306a36Sopenharmony_ci	 */
262962306a36Sopenharmony_ci	modify_len = roundup_pow_of_two(fw->size);
263062306a36Sopenharmony_ci	modify_len = min_t(u32, modify_len, BNXT_PKG_DMA_SIZE);
263162306a36Sopenharmony_ci	while (1) {
263262306a36Sopenharmony_ci		kmem = hwrm_req_dma_slice(bp, modify, modify_len, &dma_handle);
263362306a36Sopenharmony_ci		if (!kmem && modify_len > PAGE_SIZE)
263462306a36Sopenharmony_ci			modify_len /= 2;
263562306a36Sopenharmony_ci		else
263662306a36Sopenharmony_ci			break;
263762306a36Sopenharmony_ci	}
263862306a36Sopenharmony_ci	if (!kmem) {
263962306a36Sopenharmony_ci		hwrm_req_drop(bp, modify);
264062306a36Sopenharmony_ci		return -ENOMEM;
264162306a36Sopenharmony_ci	}
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	rc = hwrm_req_init(bp, install, HWRM_NVM_INSTALL_UPDATE);
264462306a36Sopenharmony_ci	if (rc) {
264562306a36Sopenharmony_ci		hwrm_req_drop(bp, modify);
264662306a36Sopenharmony_ci		return rc;
264762306a36Sopenharmony_ci	}
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	hwrm_req_timeout(bp, modify, bp->hwrm_cmd_max_timeout);
265062306a36Sopenharmony_ci	hwrm_req_timeout(bp, install, bp->hwrm_cmd_max_timeout);
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	hwrm_req_hold(bp, modify);
265362306a36Sopenharmony_ci	modify->host_src_addr = cpu_to_le64(dma_handle);
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	resp = hwrm_req_hold(bp, install);
265662306a36Sopenharmony_ci	if ((install_type & 0xffff) == 0)
265762306a36Sopenharmony_ci		install_type >>= 16;
265862306a36Sopenharmony_ci	install->install_type = cpu_to_le32(install_type);
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	do {
266162306a36Sopenharmony_ci		u32 copied = 0, len = modify_len;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci		rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE,
266462306a36Sopenharmony_ci					  BNX_DIR_ORDINAL_FIRST,
266562306a36Sopenharmony_ci					  BNX_DIR_EXT_NONE,
266662306a36Sopenharmony_ci					  &index, &item_len, NULL);
266762306a36Sopenharmony_ci		if (rc) {
266862306a36Sopenharmony_ci			BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_PKG_UPDATE_AREA_ERR);
266962306a36Sopenharmony_ci			break;
267062306a36Sopenharmony_ci		}
267162306a36Sopenharmony_ci		if (fw->size > item_len) {
267262306a36Sopenharmony_ci			BNXT_NVM_ERR_MSG(dev, extack, MSG_NO_SPACE_ERR);
267362306a36Sopenharmony_ci			rc = -EFBIG;
267462306a36Sopenharmony_ci			break;
267562306a36Sopenharmony_ci		}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci		modify->dir_idx = cpu_to_le16(index);
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci		if (fw->size > modify_len)
268062306a36Sopenharmony_ci			modify->flags = BNXT_NVM_MORE_FLAG;
268162306a36Sopenharmony_ci		while (copied < fw->size) {
268262306a36Sopenharmony_ci			u32 balance = fw->size - copied;
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci			if (balance <= modify_len) {
268562306a36Sopenharmony_ci				len = balance;
268662306a36Sopenharmony_ci				if (copied)
268762306a36Sopenharmony_ci					modify->flags |= BNXT_NVM_LAST_FLAG;
268862306a36Sopenharmony_ci			}
268962306a36Sopenharmony_ci			memcpy(kmem, fw->data + copied, len);
269062306a36Sopenharmony_ci			modify->len = cpu_to_le32(len);
269162306a36Sopenharmony_ci			modify->offset = cpu_to_le32(copied);
269262306a36Sopenharmony_ci			rc = hwrm_req_send(bp, modify);
269362306a36Sopenharmony_ci			if (rc)
269462306a36Sopenharmony_ci				goto pkg_abort;
269562306a36Sopenharmony_ci			copied += len;
269662306a36Sopenharmony_ci		}
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci		rc = hwrm_req_send_silent(bp, install);
269962306a36Sopenharmony_ci		if (!rc)
270062306a36Sopenharmony_ci			break;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci		if (defrag_attempted) {
270362306a36Sopenharmony_ci			/* We have tried to defragment already in the previous
270462306a36Sopenharmony_ci			 * iteration. Return with the result for INSTALL_UPDATE
270562306a36Sopenharmony_ci			 */
270662306a36Sopenharmony_ci			break;
270762306a36Sopenharmony_ci		}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci		cmd_err = ((struct hwrm_err_output *)resp)->cmd_err;
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci		switch (cmd_err) {
271262306a36Sopenharmony_ci		case NVM_INSTALL_UPDATE_CMD_ERR_CODE_ANTI_ROLLBACK:
271362306a36Sopenharmony_ci			BNXT_NVM_ERR_MSG(dev, extack, MSG_ANTI_ROLLBACK_ERR);
271462306a36Sopenharmony_ci			rc = -EALREADY;
271562306a36Sopenharmony_ci			break;
271662306a36Sopenharmony_ci		case NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR:
271762306a36Sopenharmony_ci			install->flags =
271862306a36Sopenharmony_ci				cpu_to_le16(NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci			rc = hwrm_req_send_silent(bp, install);
272162306a36Sopenharmony_ci			if (!rc)
272262306a36Sopenharmony_ci				break;
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci			cmd_err = ((struct hwrm_err_output *)resp)->cmd_err;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci			if (cmd_err == NVM_INSTALL_UPDATE_CMD_ERR_CODE_NO_SPACE) {
272762306a36Sopenharmony_ci				/* FW has cleared NVM area, driver will create
272862306a36Sopenharmony_ci				 * UPDATE directory and try the flash again
272962306a36Sopenharmony_ci				 */
273062306a36Sopenharmony_ci				defrag_attempted = true;
273162306a36Sopenharmony_ci				install->flags = 0;
273262306a36Sopenharmony_ci				rc = bnxt_flash_nvram(bp->dev,
273362306a36Sopenharmony_ci						      BNX_DIR_TYPE_UPDATE,
273462306a36Sopenharmony_ci						      BNX_DIR_ORDINAL_FIRST,
273562306a36Sopenharmony_ci						      0, 0, item_len, NULL, 0);
273662306a36Sopenharmony_ci				if (!rc)
273762306a36Sopenharmony_ci					break;
273862306a36Sopenharmony_ci			}
273962306a36Sopenharmony_ci			fallthrough;
274062306a36Sopenharmony_ci		default:
274162306a36Sopenharmony_ci			BNXT_NVM_ERR_MSG(dev, extack, MSG_GENERIC_FAILURE_ERR);
274262306a36Sopenharmony_ci		}
274362306a36Sopenharmony_ci	} while (defrag_attempted && !rc);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_cipkg_abort:
274662306a36Sopenharmony_ci	hwrm_req_drop(bp, modify);
274762306a36Sopenharmony_ci	hwrm_req_drop(bp, install);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	if (resp->result) {
275062306a36Sopenharmony_ci		netdev_err(dev, "PKG install error = %d, problem_item = %d\n",
275162306a36Sopenharmony_ci			   (s8)resp->result, (int)resp->problem_item);
275262306a36Sopenharmony_ci		rc = nvm_update_err_to_stderr(dev, resp->result, extack);
275362306a36Sopenharmony_ci	}
275462306a36Sopenharmony_ci	if (rc == -EACCES)
275562306a36Sopenharmony_ci		bnxt_print_admin_err(bp);
275662306a36Sopenharmony_ci	return rc;
275762306a36Sopenharmony_ci}
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_cistatic int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
276062306a36Sopenharmony_ci					u32 install_type, struct netlink_ext_ack *extack)
276162306a36Sopenharmony_ci{
276262306a36Sopenharmony_ci	const struct firmware *fw;
276362306a36Sopenharmony_ci	int rc;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	rc = request_firmware(&fw, filename, &dev->dev);
276662306a36Sopenharmony_ci	if (rc != 0) {
276762306a36Sopenharmony_ci		netdev_err(dev, "PKG error %d requesting file: %s\n",
276862306a36Sopenharmony_ci			   rc, filename);
276962306a36Sopenharmony_ci		return rc;
277062306a36Sopenharmony_ci	}
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	rc = bnxt_flash_package_from_fw_obj(dev, fw, install_type, extack);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	release_firmware(fw);
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	return rc;
277762306a36Sopenharmony_ci}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_cistatic int bnxt_flash_device(struct net_device *dev,
278062306a36Sopenharmony_ci			     struct ethtool_flash *flash)
278162306a36Sopenharmony_ci{
278262306a36Sopenharmony_ci	if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) {
278362306a36Sopenharmony_ci		netdev_err(dev, "flashdev not supported from a virtual function\n");
278462306a36Sopenharmony_ci		return -EINVAL;
278562306a36Sopenharmony_ci	}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	if (flash->region == ETHTOOL_FLASH_ALL_REGIONS ||
278862306a36Sopenharmony_ci	    flash->region > 0xffff)
278962306a36Sopenharmony_ci		return bnxt_flash_package_from_file(dev, flash->data,
279062306a36Sopenharmony_ci						    flash->region, NULL);
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	return bnxt_flash_firmware_from_file(dev, flash->region, flash->data);
279362306a36Sopenharmony_ci}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_cistatic int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length)
279662306a36Sopenharmony_ci{
279762306a36Sopenharmony_ci	struct hwrm_nvm_get_dir_info_output *output;
279862306a36Sopenharmony_ci	struct hwrm_nvm_get_dir_info_input *req;
279962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
280062306a36Sopenharmony_ci	int rc;
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_INFO);
280362306a36Sopenharmony_ci	if (rc)
280462306a36Sopenharmony_ci		return rc;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	output = hwrm_req_hold(bp, req);
280762306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
280862306a36Sopenharmony_ci	if (!rc) {
280962306a36Sopenharmony_ci		*entries = le32_to_cpu(output->entries);
281062306a36Sopenharmony_ci		*length = le32_to_cpu(output->entry_length);
281162306a36Sopenharmony_ci	}
281262306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
281362306a36Sopenharmony_ci	return rc;
281462306a36Sopenharmony_ci}
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_cistatic int bnxt_get_eeprom_len(struct net_device *dev)
281762306a36Sopenharmony_ci{
281862306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	if (BNXT_VF(bp))
282162306a36Sopenharmony_ci		return 0;
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	/* The -1 return value allows the entire 32-bit range of offsets to be
282462306a36Sopenharmony_ci	 * passed via the ethtool command-line utility.
282562306a36Sopenharmony_ci	 */
282662306a36Sopenharmony_ci	return -1;
282762306a36Sopenharmony_ci}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_cistatic int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data)
283062306a36Sopenharmony_ci{
283162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
283262306a36Sopenharmony_ci	int rc;
283362306a36Sopenharmony_ci	u32 dir_entries;
283462306a36Sopenharmony_ci	u32 entry_length;
283562306a36Sopenharmony_ci	u8 *buf;
283662306a36Sopenharmony_ci	size_t buflen;
283762306a36Sopenharmony_ci	dma_addr_t dma_handle;
283862306a36Sopenharmony_ci	struct hwrm_nvm_get_dir_entries_input *req;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	rc = nvm_get_dir_info(dev, &dir_entries, &entry_length);
284162306a36Sopenharmony_ci	if (rc != 0)
284262306a36Sopenharmony_ci		return rc;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	if (!dir_entries || !entry_length)
284562306a36Sopenharmony_ci		return -EIO;
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	/* Insert 2 bytes of directory info (count and size of entries) */
284862306a36Sopenharmony_ci	if (len < 2)
284962306a36Sopenharmony_ci		return -EINVAL;
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	*data++ = dir_entries;
285262306a36Sopenharmony_ci	*data++ = entry_length;
285362306a36Sopenharmony_ci	len -= 2;
285462306a36Sopenharmony_ci	memset(data, 0xff, len);
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_GET_DIR_ENTRIES);
285762306a36Sopenharmony_ci	if (rc)
285862306a36Sopenharmony_ci		return rc;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	buflen = mul_u32_u32(dir_entries, entry_length);
286162306a36Sopenharmony_ci	buf = hwrm_req_dma_slice(bp, req, buflen, &dma_handle);
286262306a36Sopenharmony_ci	if (!buf) {
286362306a36Sopenharmony_ci		hwrm_req_drop(bp, req);
286462306a36Sopenharmony_ci		return -ENOMEM;
286562306a36Sopenharmony_ci	}
286662306a36Sopenharmony_ci	req->host_dest_addr = cpu_to_le64(dma_handle);
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	hwrm_req_hold(bp, req); /* hold the slice */
286962306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
287062306a36Sopenharmony_ci	if (rc == 0)
287162306a36Sopenharmony_ci		memcpy(data, buf, len > buflen ? buflen : len);
287262306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
287362306a36Sopenharmony_ci	return rc;
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ciint bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset,
287762306a36Sopenharmony_ci			u32 length, u8 *data)
287862306a36Sopenharmony_ci{
287962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
288062306a36Sopenharmony_ci	int rc;
288162306a36Sopenharmony_ci	u8 *buf;
288262306a36Sopenharmony_ci	dma_addr_t dma_handle;
288362306a36Sopenharmony_ci	struct hwrm_nvm_read_input *req;
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	if (!length)
288662306a36Sopenharmony_ci		return -EINVAL;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_READ);
288962306a36Sopenharmony_ci	if (rc)
289062306a36Sopenharmony_ci		return rc;
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	buf = hwrm_req_dma_slice(bp, req, length, &dma_handle);
289362306a36Sopenharmony_ci	if (!buf) {
289462306a36Sopenharmony_ci		hwrm_req_drop(bp, req);
289562306a36Sopenharmony_ci		return -ENOMEM;
289662306a36Sopenharmony_ci	}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	req->host_dest_addr = cpu_to_le64(dma_handle);
289962306a36Sopenharmony_ci	req->dir_idx = cpu_to_le16(index);
290062306a36Sopenharmony_ci	req->offset = cpu_to_le32(offset);
290162306a36Sopenharmony_ci	req->len = cpu_to_le32(length);
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	hwrm_req_hold(bp, req); /* hold the slice */
290462306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
290562306a36Sopenharmony_ci	if (rc == 0)
290662306a36Sopenharmony_ci		memcpy(data, buf, length);
290762306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
290862306a36Sopenharmony_ci	return rc;
290962306a36Sopenharmony_ci}
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ciint bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
291262306a36Sopenharmony_ci			 u16 ext, u16 *index, u32 *item_length,
291362306a36Sopenharmony_ci			 u32 *data_length)
291462306a36Sopenharmony_ci{
291562306a36Sopenharmony_ci	struct hwrm_nvm_find_dir_entry_output *output;
291662306a36Sopenharmony_ci	struct hwrm_nvm_find_dir_entry_input *req;
291762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
291862306a36Sopenharmony_ci	int rc;
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_FIND_DIR_ENTRY);
292162306a36Sopenharmony_ci	if (rc)
292262306a36Sopenharmony_ci		return rc;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	req->enables = 0;
292562306a36Sopenharmony_ci	req->dir_idx = 0;
292662306a36Sopenharmony_ci	req->dir_type = cpu_to_le16(type);
292762306a36Sopenharmony_ci	req->dir_ordinal = cpu_to_le16(ordinal);
292862306a36Sopenharmony_ci	req->dir_ext = cpu_to_le16(ext);
292962306a36Sopenharmony_ci	req->opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ;
293062306a36Sopenharmony_ci	output = hwrm_req_hold(bp, req);
293162306a36Sopenharmony_ci	rc = hwrm_req_send_silent(bp, req);
293262306a36Sopenharmony_ci	if (rc == 0) {
293362306a36Sopenharmony_ci		if (index)
293462306a36Sopenharmony_ci			*index = le16_to_cpu(output->dir_idx);
293562306a36Sopenharmony_ci		if (item_length)
293662306a36Sopenharmony_ci			*item_length = le32_to_cpu(output->dir_item_length);
293762306a36Sopenharmony_ci		if (data_length)
293862306a36Sopenharmony_ci			*data_length = le32_to_cpu(output->dir_data_length);
293962306a36Sopenharmony_ci	}
294062306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
294162306a36Sopenharmony_ci	return rc;
294262306a36Sopenharmony_ci}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_cistatic char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen)
294562306a36Sopenharmony_ci{
294662306a36Sopenharmony_ci	char	*retval = NULL;
294762306a36Sopenharmony_ci	char	*p;
294862306a36Sopenharmony_ci	char	*value;
294962306a36Sopenharmony_ci	int	field = 0;
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci	if (datalen < 1)
295262306a36Sopenharmony_ci		return NULL;
295362306a36Sopenharmony_ci	/* null-terminate the log data (removing last '\n'): */
295462306a36Sopenharmony_ci	data[datalen - 1] = 0;
295562306a36Sopenharmony_ci	for (p = data; *p != 0; p++) {
295662306a36Sopenharmony_ci		field = 0;
295762306a36Sopenharmony_ci		retval = NULL;
295862306a36Sopenharmony_ci		while (*p != 0 && *p != '\n') {
295962306a36Sopenharmony_ci			value = p;
296062306a36Sopenharmony_ci			while (*p != 0 && *p != '\t' && *p != '\n')
296162306a36Sopenharmony_ci				p++;
296262306a36Sopenharmony_ci			if (field == desired_field)
296362306a36Sopenharmony_ci				retval = value;
296462306a36Sopenharmony_ci			if (*p != '\t')
296562306a36Sopenharmony_ci				break;
296662306a36Sopenharmony_ci			*p = 0;
296762306a36Sopenharmony_ci			field++;
296862306a36Sopenharmony_ci			p++;
296962306a36Sopenharmony_ci		}
297062306a36Sopenharmony_ci		if (*p == 0)
297162306a36Sopenharmony_ci			break;
297262306a36Sopenharmony_ci		*p = 0;
297362306a36Sopenharmony_ci	}
297462306a36Sopenharmony_ci	return retval;
297562306a36Sopenharmony_ci}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ciint bnxt_get_pkginfo(struct net_device *dev, char *ver, int size)
297862306a36Sopenharmony_ci{
297962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
298062306a36Sopenharmony_ci	u16 index = 0;
298162306a36Sopenharmony_ci	char *pkgver;
298262306a36Sopenharmony_ci	u32 pkglen;
298362306a36Sopenharmony_ci	u8 *pkgbuf;
298462306a36Sopenharmony_ci	int rc;
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG,
298762306a36Sopenharmony_ci				  BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
298862306a36Sopenharmony_ci				  &index, NULL, &pkglen);
298962306a36Sopenharmony_ci	if (rc)
299062306a36Sopenharmony_ci		return rc;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	pkgbuf = kzalloc(pkglen, GFP_KERNEL);
299362306a36Sopenharmony_ci	if (!pkgbuf) {
299462306a36Sopenharmony_ci		dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n",
299562306a36Sopenharmony_ci			pkglen);
299662306a36Sopenharmony_ci		return -ENOMEM;
299762306a36Sopenharmony_ci	}
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	rc = bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf);
300062306a36Sopenharmony_ci	if (rc)
300162306a36Sopenharmony_ci		goto err;
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf,
300462306a36Sopenharmony_ci				   pkglen);
300562306a36Sopenharmony_ci	if (pkgver && *pkgver != 0 && isdigit(*pkgver))
300662306a36Sopenharmony_ci		strscpy(ver, pkgver, size);
300762306a36Sopenharmony_ci	else
300862306a36Sopenharmony_ci		rc = -ENOENT;
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_cierr:
301162306a36Sopenharmony_ci	kfree(pkgbuf);
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	return rc;
301462306a36Sopenharmony_ci}
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_cistatic void bnxt_get_pkgver(struct net_device *dev)
301762306a36Sopenharmony_ci{
301862306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
301962306a36Sopenharmony_ci	char buf[FW_VER_STR_LEN];
302062306a36Sopenharmony_ci	int len;
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) {
302362306a36Sopenharmony_ci		len = strlen(bp->fw_ver_str);
302462306a36Sopenharmony_ci		snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1,
302562306a36Sopenharmony_ci			 "/pkg %s", buf);
302662306a36Sopenharmony_ci	}
302762306a36Sopenharmony_ci}
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_cistatic int bnxt_get_eeprom(struct net_device *dev,
303062306a36Sopenharmony_ci			   struct ethtool_eeprom *eeprom,
303162306a36Sopenharmony_ci			   u8 *data)
303262306a36Sopenharmony_ci{
303362306a36Sopenharmony_ci	u32 index;
303462306a36Sopenharmony_ci	u32 offset;
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	if (eeprom->offset == 0) /* special offset value to get directory */
303762306a36Sopenharmony_ci		return bnxt_get_nvram_directory(dev, eeprom->len, data);
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	index = eeprom->offset >> 24;
304062306a36Sopenharmony_ci	offset = eeprom->offset & 0xffffff;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	if (index == 0) {
304362306a36Sopenharmony_ci		netdev_err(dev, "unsupported index value: %d\n", index);
304462306a36Sopenharmony_ci		return -EINVAL;
304562306a36Sopenharmony_ci	}
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data);
304862306a36Sopenharmony_ci}
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_cistatic int bnxt_erase_nvram_directory(struct net_device *dev, u8 index)
305162306a36Sopenharmony_ci{
305262306a36Sopenharmony_ci	struct hwrm_nvm_erase_dir_entry_input *req;
305362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
305462306a36Sopenharmony_ci	int rc;
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_NVM_ERASE_DIR_ENTRY);
305762306a36Sopenharmony_ci	if (rc)
305862306a36Sopenharmony_ci		return rc;
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	req->dir_idx = cpu_to_le16(index);
306162306a36Sopenharmony_ci	return hwrm_req_send(bp, req);
306262306a36Sopenharmony_ci}
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_cistatic int bnxt_set_eeprom(struct net_device *dev,
306562306a36Sopenharmony_ci			   struct ethtool_eeprom *eeprom,
306662306a36Sopenharmony_ci			   u8 *data)
306762306a36Sopenharmony_ci{
306862306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
306962306a36Sopenharmony_ci	u8 index, dir_op;
307062306a36Sopenharmony_ci	u16 type, ext, ordinal, attr;
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci	if (!BNXT_PF(bp)) {
307362306a36Sopenharmony_ci		netdev_err(dev, "NVM write not supported from a virtual function\n");
307462306a36Sopenharmony_ci		return -EINVAL;
307562306a36Sopenharmony_ci	}
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	type = eeprom->magic >> 16;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	if (type == 0xffff) { /* special value for directory operations */
308062306a36Sopenharmony_ci		index = eeprom->magic & 0xff;
308162306a36Sopenharmony_ci		dir_op = eeprom->magic >> 8;
308262306a36Sopenharmony_ci		if (index == 0)
308362306a36Sopenharmony_ci			return -EINVAL;
308462306a36Sopenharmony_ci		switch (dir_op) {
308562306a36Sopenharmony_ci		case 0x0e: /* erase */
308662306a36Sopenharmony_ci			if (eeprom->offset != ~eeprom->magic)
308762306a36Sopenharmony_ci				return -EINVAL;
308862306a36Sopenharmony_ci			return bnxt_erase_nvram_directory(dev, index - 1);
308962306a36Sopenharmony_ci		default:
309062306a36Sopenharmony_ci			return -EINVAL;
309162306a36Sopenharmony_ci		}
309262306a36Sopenharmony_ci	}
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	/* Create or re-write an NVM item: */
309562306a36Sopenharmony_ci	if (bnxt_dir_type_is_executable(type))
309662306a36Sopenharmony_ci		return -EOPNOTSUPP;
309762306a36Sopenharmony_ci	ext = eeprom->magic & 0xffff;
309862306a36Sopenharmony_ci	ordinal = eeprom->offset >> 16;
309962306a36Sopenharmony_ci	attr = eeprom->offset & 0xffff;
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	return bnxt_flash_nvram(dev, type, ordinal, ext, attr, 0, data,
310262306a36Sopenharmony_ci				eeprom->len);
310362306a36Sopenharmony_ci}
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_cistatic int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
310662306a36Sopenharmony_ci{
310762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
310862306a36Sopenharmony_ci	struct ethtool_eee *eee = &bp->eee;
310962306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
311062306a36Sopenharmony_ci	u32 advertising;
311162306a36Sopenharmony_ci	int rc = 0;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
311462306a36Sopenharmony_ci		return -EOPNOTSUPP;
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP))
311762306a36Sopenharmony_ci		return -EOPNOTSUPP;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	mutex_lock(&bp->link_lock);
312062306a36Sopenharmony_ci	advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
312162306a36Sopenharmony_ci	if (!edata->eee_enabled)
312262306a36Sopenharmony_ci		goto eee_ok;
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
312562306a36Sopenharmony_ci		netdev_warn(dev, "EEE requires autoneg\n");
312662306a36Sopenharmony_ci		rc = -EINVAL;
312762306a36Sopenharmony_ci		goto eee_exit;
312862306a36Sopenharmony_ci	}
312962306a36Sopenharmony_ci	if (edata->tx_lpi_enabled) {
313062306a36Sopenharmony_ci		if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
313162306a36Sopenharmony_ci				       edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
313262306a36Sopenharmony_ci			netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
313362306a36Sopenharmony_ci				    bp->lpi_tmr_lo, bp->lpi_tmr_hi);
313462306a36Sopenharmony_ci			rc = -EINVAL;
313562306a36Sopenharmony_ci			goto eee_exit;
313662306a36Sopenharmony_ci		} else if (!bp->lpi_tmr_hi) {
313762306a36Sopenharmony_ci			edata->tx_lpi_timer = eee->tx_lpi_timer;
313862306a36Sopenharmony_ci		}
313962306a36Sopenharmony_ci	}
314062306a36Sopenharmony_ci	if (!edata->advertised) {
314162306a36Sopenharmony_ci		edata->advertised = advertising & eee->supported;
314262306a36Sopenharmony_ci	} else if (edata->advertised & ~advertising) {
314362306a36Sopenharmony_ci		netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
314462306a36Sopenharmony_ci			    edata->advertised, advertising);
314562306a36Sopenharmony_ci		rc = -EINVAL;
314662306a36Sopenharmony_ci		goto eee_exit;
314762306a36Sopenharmony_ci	}
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	eee->advertised = edata->advertised;
315062306a36Sopenharmony_ci	eee->tx_lpi_enabled = edata->tx_lpi_enabled;
315162306a36Sopenharmony_ci	eee->tx_lpi_timer = edata->tx_lpi_timer;
315262306a36Sopenharmony_cieee_ok:
315362306a36Sopenharmony_ci	eee->eee_enabled = edata->eee_enabled;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	if (netif_running(dev))
315662306a36Sopenharmony_ci		rc = bnxt_hwrm_set_link_setting(bp, false, true);
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_cieee_exit:
315962306a36Sopenharmony_ci	mutex_unlock(&bp->link_lock);
316062306a36Sopenharmony_ci	return rc;
316162306a36Sopenharmony_ci}
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_cistatic int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata)
316462306a36Sopenharmony_ci{
316562306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ci	if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP))
316862306a36Sopenharmony_ci		return -EOPNOTSUPP;
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci	*edata = bp->eee;
317162306a36Sopenharmony_ci	if (!bp->eee.eee_enabled) {
317262306a36Sopenharmony_ci		/* Preserve tx_lpi_timer so that the last value will be used
317362306a36Sopenharmony_ci		 * by default when it is re-enabled.
317462306a36Sopenharmony_ci		 */
317562306a36Sopenharmony_ci		edata->advertised = 0;
317662306a36Sopenharmony_ci		edata->tx_lpi_enabled = 0;
317762306a36Sopenharmony_ci	}
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	if (!bp->eee.eee_active)
318062306a36Sopenharmony_ci		edata->lp_advertised = 0;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	return 0;
318362306a36Sopenharmony_ci}
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_cistatic int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr,
318662306a36Sopenharmony_ci					    u16 page_number, u8 bank,
318762306a36Sopenharmony_ci					    u16 start_addr, u16 data_length,
318862306a36Sopenharmony_ci					    u8 *buf)
318962306a36Sopenharmony_ci{
319062306a36Sopenharmony_ci	struct hwrm_port_phy_i2c_read_output *output;
319162306a36Sopenharmony_ci	struct hwrm_port_phy_i2c_read_input *req;
319262306a36Sopenharmony_ci	int rc, byte_offset = 0;
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_I2C_READ);
319562306a36Sopenharmony_ci	if (rc)
319662306a36Sopenharmony_ci		return rc;
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci	output = hwrm_req_hold(bp, req);
319962306a36Sopenharmony_ci	req->i2c_slave_addr = i2c_addr;
320062306a36Sopenharmony_ci	req->page_number = cpu_to_le16(page_number);
320162306a36Sopenharmony_ci	req->port_id = cpu_to_le16(bp->pf.port_id);
320262306a36Sopenharmony_ci	do {
320362306a36Sopenharmony_ci		u16 xfer_size;
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci		xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE);
320662306a36Sopenharmony_ci		data_length -= xfer_size;
320762306a36Sopenharmony_ci		req->page_offset = cpu_to_le16(start_addr + byte_offset);
320862306a36Sopenharmony_ci		req->data_length = xfer_size;
320962306a36Sopenharmony_ci		req->enables =
321062306a36Sopenharmony_ci			cpu_to_le32((start_addr + byte_offset ?
321162306a36Sopenharmony_ci				     PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET :
321262306a36Sopenharmony_ci				     0) |
321362306a36Sopenharmony_ci				    (bank ?
321462306a36Sopenharmony_ci				     PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER :
321562306a36Sopenharmony_ci				     0));
321662306a36Sopenharmony_ci		rc = hwrm_req_send(bp, req);
321762306a36Sopenharmony_ci		if (!rc)
321862306a36Sopenharmony_ci			memcpy(buf + byte_offset, output->data, xfer_size);
321962306a36Sopenharmony_ci		byte_offset += xfer_size;
322062306a36Sopenharmony_ci	} while (!rc && data_length > 0);
322162306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	return rc;
322462306a36Sopenharmony_ci}
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_cistatic int bnxt_get_module_info(struct net_device *dev,
322762306a36Sopenharmony_ci				struct ethtool_modinfo *modinfo)
322862306a36Sopenharmony_ci{
322962306a36Sopenharmony_ci	u8 data[SFF_DIAG_SUPPORT_OFFSET + 1];
323062306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
323162306a36Sopenharmony_ci	int rc;
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	/* No point in going further if phy status indicates
323462306a36Sopenharmony_ci	 * module is not inserted or if it is powered down or
323562306a36Sopenharmony_ci	 * if it is of type 10GBase-T
323662306a36Sopenharmony_ci	 */
323762306a36Sopenharmony_ci	if (bp->link_info.module_status >
323862306a36Sopenharmony_ci		PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG)
323962306a36Sopenharmony_ci		return -EOPNOTSUPP;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	/* This feature is not supported in older firmware versions */
324262306a36Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10202)
324362306a36Sopenharmony_ci		return -EOPNOTSUPP;
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci	rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0,
324662306a36Sopenharmony_ci					      SFF_DIAG_SUPPORT_OFFSET + 1,
324762306a36Sopenharmony_ci					      data);
324862306a36Sopenharmony_ci	if (!rc) {
324962306a36Sopenharmony_ci		u8 module_id = data[0];
325062306a36Sopenharmony_ci		u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET];
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci		switch (module_id) {
325362306a36Sopenharmony_ci		case SFF_MODULE_ID_SFP:
325462306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8472;
325562306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
325662306a36Sopenharmony_ci			if (!diag_supported)
325762306a36Sopenharmony_ci				modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
325862306a36Sopenharmony_ci			break;
325962306a36Sopenharmony_ci		case SFF_MODULE_ID_QSFP:
326062306a36Sopenharmony_ci		case SFF_MODULE_ID_QSFP_PLUS:
326162306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8436;
326262306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
326362306a36Sopenharmony_ci			break;
326462306a36Sopenharmony_ci		case SFF_MODULE_ID_QSFP28:
326562306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8636;
326662306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
326762306a36Sopenharmony_ci			break;
326862306a36Sopenharmony_ci		default:
326962306a36Sopenharmony_ci			rc = -EOPNOTSUPP;
327062306a36Sopenharmony_ci			break;
327162306a36Sopenharmony_ci		}
327262306a36Sopenharmony_ci	}
327362306a36Sopenharmony_ci	return rc;
327462306a36Sopenharmony_ci}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_cistatic int bnxt_get_module_eeprom(struct net_device *dev,
327762306a36Sopenharmony_ci				  struct ethtool_eeprom *eeprom,
327862306a36Sopenharmony_ci				  u8 *data)
327962306a36Sopenharmony_ci{
328062306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
328162306a36Sopenharmony_ci	u16  start = eeprom->offset, length = eeprom->len;
328262306a36Sopenharmony_ci	int rc = 0;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	memset(data, 0, eeprom->len);
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	/* Read A0 portion of the EEPROM */
328762306a36Sopenharmony_ci	if (start < ETH_MODULE_SFF_8436_LEN) {
328862306a36Sopenharmony_ci		if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN)
328962306a36Sopenharmony_ci			length = ETH_MODULE_SFF_8436_LEN - start;
329062306a36Sopenharmony_ci		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0,
329162306a36Sopenharmony_ci						      start, length, data);
329262306a36Sopenharmony_ci		if (rc)
329362306a36Sopenharmony_ci			return rc;
329462306a36Sopenharmony_ci		start += length;
329562306a36Sopenharmony_ci		data += length;
329662306a36Sopenharmony_ci		length = eeprom->len - length;
329762306a36Sopenharmony_ci	}
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	/* Read A2 portion of the EEPROM */
330062306a36Sopenharmony_ci	if (length) {
330162306a36Sopenharmony_ci		start -= ETH_MODULE_SFF_8436_LEN;
330262306a36Sopenharmony_ci		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0,
330362306a36Sopenharmony_ci						      start, length, data);
330462306a36Sopenharmony_ci	}
330562306a36Sopenharmony_ci	return rc;
330662306a36Sopenharmony_ci}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_cistatic int bnxt_get_module_status(struct bnxt *bp, struct netlink_ext_ack *extack)
330962306a36Sopenharmony_ci{
331062306a36Sopenharmony_ci	if (bp->link_info.module_status <=
331162306a36Sopenharmony_ci	    PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG)
331262306a36Sopenharmony_ci		return 0;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	switch (bp->link_info.module_status) {
331562306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN:
331662306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down");
331762306a36Sopenharmony_ci		break;
331862306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED:
331962306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted");
332062306a36Sopenharmony_ci		break;
332162306a36Sopenharmony_ci	case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT:
332262306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Transceiver module disabled due to current fault");
332362306a36Sopenharmony_ci		break;
332462306a36Sopenharmony_ci	default:
332562306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Unknown error");
332662306a36Sopenharmony_ci		break;
332762306a36Sopenharmony_ci	}
332862306a36Sopenharmony_ci	return -EINVAL;
332962306a36Sopenharmony_ci}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_cistatic int bnxt_get_module_eeprom_by_page(struct net_device *dev,
333262306a36Sopenharmony_ci					  const struct ethtool_module_eeprom *page_data,
333362306a36Sopenharmony_ci					  struct netlink_ext_ack *extack)
333462306a36Sopenharmony_ci{
333562306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
333662306a36Sopenharmony_ci	int rc;
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci	rc = bnxt_get_module_status(bp, extack);
333962306a36Sopenharmony_ci	if (rc)
334062306a36Sopenharmony_ci		return rc;
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10202) {
334362306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Firmware version too old");
334462306a36Sopenharmony_ci		return -EINVAL;
334562306a36Sopenharmony_ci	}
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci	if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) {
334862306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection");
334962306a36Sopenharmony_ci		return -EINVAL;
335062306a36Sopenharmony_ci	}
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1,
335362306a36Sopenharmony_ci					      page_data->page, page_data->bank,
335462306a36Sopenharmony_ci					      page_data->offset,
335562306a36Sopenharmony_ci					      page_data->length,
335662306a36Sopenharmony_ci					      page_data->data);
335762306a36Sopenharmony_ci	if (rc) {
335862306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed");
335962306a36Sopenharmony_ci		return rc;
336062306a36Sopenharmony_ci	}
336162306a36Sopenharmony_ci	return page_data->length;
336262306a36Sopenharmony_ci}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_cistatic int bnxt_nway_reset(struct net_device *dev)
336562306a36Sopenharmony_ci{
336662306a36Sopenharmony_ci	int rc = 0;
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
336962306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
337062306a36Sopenharmony_ci
337162306a36Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
337262306a36Sopenharmony_ci		return -EOPNOTSUPP;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
337562306a36Sopenharmony_ci		return -EINVAL;
337662306a36Sopenharmony_ci
337762306a36Sopenharmony_ci	if (netif_running(dev))
337862306a36Sopenharmony_ci		rc = bnxt_hwrm_set_link_setting(bp, true, false);
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	return rc;
338162306a36Sopenharmony_ci}
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_cistatic int bnxt_set_phys_id(struct net_device *dev,
338462306a36Sopenharmony_ci			    enum ethtool_phys_id_state state)
338562306a36Sopenharmony_ci{
338662306a36Sopenharmony_ci	struct hwrm_port_led_cfg_input *req;
338762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
338862306a36Sopenharmony_ci	struct bnxt_pf_info *pf = &bp->pf;
338962306a36Sopenharmony_ci	struct bnxt_led_cfg *led_cfg;
339062306a36Sopenharmony_ci	u8 led_state;
339162306a36Sopenharmony_ci	__le16 duration;
339262306a36Sopenharmony_ci	int rc, i;
339362306a36Sopenharmony_ci
339462306a36Sopenharmony_ci	if (!bp->num_leds || BNXT_VF(bp))
339562306a36Sopenharmony_ci		return -EOPNOTSUPP;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	if (state == ETHTOOL_ID_ACTIVE) {
339862306a36Sopenharmony_ci		led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT;
339962306a36Sopenharmony_ci		duration = cpu_to_le16(500);
340062306a36Sopenharmony_ci	} else if (state == ETHTOOL_ID_INACTIVE) {
340162306a36Sopenharmony_ci		led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT;
340262306a36Sopenharmony_ci		duration = cpu_to_le16(0);
340362306a36Sopenharmony_ci	} else {
340462306a36Sopenharmony_ci		return -EINVAL;
340562306a36Sopenharmony_ci	}
340662306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_PORT_LED_CFG);
340762306a36Sopenharmony_ci	if (rc)
340862306a36Sopenharmony_ci		return rc;
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	req->port_id = cpu_to_le16(pf->port_id);
341162306a36Sopenharmony_ci	req->num_leds = bp->num_leds;
341262306a36Sopenharmony_ci	led_cfg = (struct bnxt_led_cfg *)&req->led0_id;
341362306a36Sopenharmony_ci	for (i = 0; i < bp->num_leds; i++, led_cfg++) {
341462306a36Sopenharmony_ci		req->enables |= BNXT_LED_DFLT_ENABLES(i);
341562306a36Sopenharmony_ci		led_cfg->led_id = bp->leds[i].led_id;
341662306a36Sopenharmony_ci		led_cfg->led_state = led_state;
341762306a36Sopenharmony_ci		led_cfg->led_blink_on = duration;
341862306a36Sopenharmony_ci		led_cfg->led_blink_off = duration;
341962306a36Sopenharmony_ci		led_cfg->led_group_id = bp->leds[i].led_group_id;
342062306a36Sopenharmony_ci	}
342162306a36Sopenharmony_ci	return hwrm_req_send(bp, req);
342262306a36Sopenharmony_ci}
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_cistatic int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring)
342562306a36Sopenharmony_ci{
342662306a36Sopenharmony_ci	struct hwrm_selftest_irq_input *req;
342762306a36Sopenharmony_ci	int rc;
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_SELFTEST_IRQ);
343062306a36Sopenharmony_ci	if (rc)
343162306a36Sopenharmony_ci		return rc;
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci	req->cmpl_ring = cpu_to_le16(cmpl_ring);
343462306a36Sopenharmony_ci	return hwrm_req_send(bp, req);
343562306a36Sopenharmony_ci}
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_cistatic int bnxt_test_irq(struct bnxt *bp)
343862306a36Sopenharmony_ci{
343962306a36Sopenharmony_ci	int i;
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci	for (i = 0; i < bp->cp_nr_rings; i++) {
344262306a36Sopenharmony_ci		u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id;
344362306a36Sopenharmony_ci		int rc;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci		rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring);
344662306a36Sopenharmony_ci		if (rc)
344762306a36Sopenharmony_ci			return rc;
344862306a36Sopenharmony_ci	}
344962306a36Sopenharmony_ci	return 0;
345062306a36Sopenharmony_ci}
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_cistatic int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable)
345362306a36Sopenharmony_ci{
345462306a36Sopenharmony_ci	struct hwrm_port_mac_cfg_input *req;
345562306a36Sopenharmony_ci	int rc;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG);
345862306a36Sopenharmony_ci	if (rc)
345962306a36Sopenharmony_ci		return rc;
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK);
346262306a36Sopenharmony_ci	if (enable)
346362306a36Sopenharmony_ci		req->lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL;
346462306a36Sopenharmony_ci	else
346562306a36Sopenharmony_ci		req->lpbk = PORT_MAC_CFG_REQ_LPBK_NONE;
346662306a36Sopenharmony_ci	return hwrm_req_send(bp, req);
346762306a36Sopenharmony_ci}
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_cistatic int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds)
347062306a36Sopenharmony_ci{
347162306a36Sopenharmony_ci	struct hwrm_port_phy_qcaps_output *resp;
347262306a36Sopenharmony_ci	struct hwrm_port_phy_qcaps_input *req;
347362306a36Sopenharmony_ci	int rc;
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_QCAPS);
347662306a36Sopenharmony_ci	if (rc)
347762306a36Sopenharmony_ci		return rc;
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci	resp = hwrm_req_hold(bp, req);
348062306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
348162306a36Sopenharmony_ci	if (!rc)
348262306a36Sopenharmony_ci		*force_speeds = le16_to_cpu(resp->supported_speeds_force_mode);
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
348562306a36Sopenharmony_ci	return rc;
348662306a36Sopenharmony_ci}
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_cistatic int bnxt_disable_an_for_lpbk(struct bnxt *bp,
348962306a36Sopenharmony_ci				    struct hwrm_port_phy_cfg_input *req)
349062306a36Sopenharmony_ci{
349162306a36Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
349262306a36Sopenharmony_ci	u16 fw_advertising;
349362306a36Sopenharmony_ci	u16 fw_speed;
349462306a36Sopenharmony_ci	int rc;
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	if (!link_info->autoneg ||
349762306a36Sopenharmony_ci	    (bp->phy_flags & BNXT_PHY_FL_AN_PHY_LPBK))
349862306a36Sopenharmony_ci		return 0;
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	rc = bnxt_query_force_speeds(bp, &fw_advertising);
350162306a36Sopenharmony_ci	if (rc)
350262306a36Sopenharmony_ci		return rc;
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
350562306a36Sopenharmony_ci	if (BNXT_LINK_IS_UP(bp))
350662306a36Sopenharmony_ci		fw_speed = bp->link_info.link_speed;
350762306a36Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB)
350862306a36Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
350962306a36Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB)
351062306a36Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
351162306a36Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB)
351262306a36Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
351362306a36Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB)
351462306a36Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	req->force_link_speed = cpu_to_le16(fw_speed);
351762306a36Sopenharmony_ci	req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE |
351862306a36Sopenharmony_ci				  PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
351962306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
352062306a36Sopenharmony_ci	req->flags = 0;
352162306a36Sopenharmony_ci	req->force_link_speed = cpu_to_le16(0);
352262306a36Sopenharmony_ci	return rc;
352362306a36Sopenharmony_ci}
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_cistatic int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext)
352662306a36Sopenharmony_ci{
352762306a36Sopenharmony_ci	struct hwrm_port_phy_cfg_input *req;
352862306a36Sopenharmony_ci	int rc;
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_PORT_PHY_CFG);
353162306a36Sopenharmony_ci	if (rc)
353262306a36Sopenharmony_ci		return rc;
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	/* prevent bnxt_disable_an_for_lpbk() from consuming the request */
353562306a36Sopenharmony_ci	hwrm_req_hold(bp, req);
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	if (enable) {
353862306a36Sopenharmony_ci		bnxt_disable_an_for_lpbk(bp, req);
353962306a36Sopenharmony_ci		if (ext)
354062306a36Sopenharmony_ci			req->lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL;
354162306a36Sopenharmony_ci		else
354262306a36Sopenharmony_ci			req->lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL;
354362306a36Sopenharmony_ci	} else {
354462306a36Sopenharmony_ci		req->lpbk = PORT_PHY_CFG_REQ_LPBK_NONE;
354562306a36Sopenharmony_ci	}
354662306a36Sopenharmony_ci	req->enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK);
354762306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
354862306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
354962306a36Sopenharmony_ci	return rc;
355062306a36Sopenharmony_ci}
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_cistatic int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
355362306a36Sopenharmony_ci			    u32 raw_cons, int pkt_size)
355462306a36Sopenharmony_ci{
355562306a36Sopenharmony_ci	struct bnxt_napi *bnapi = cpr->bnapi;
355662306a36Sopenharmony_ci	struct bnxt_rx_ring_info *rxr;
355762306a36Sopenharmony_ci	struct bnxt_sw_rx_bd *rx_buf;
355862306a36Sopenharmony_ci	struct rx_cmp *rxcmp;
355962306a36Sopenharmony_ci	u16 cp_cons, cons;
356062306a36Sopenharmony_ci	u8 *data;
356162306a36Sopenharmony_ci	u32 len;
356262306a36Sopenharmony_ci	int i;
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	rxr = bnapi->rx_ring;
356562306a36Sopenharmony_ci	cp_cons = RING_CMP(raw_cons);
356662306a36Sopenharmony_ci	rxcmp = (struct rx_cmp *)
356762306a36Sopenharmony_ci		&cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
356862306a36Sopenharmony_ci	cons = rxcmp->rx_cmp_opaque;
356962306a36Sopenharmony_ci	rx_buf = &rxr->rx_buf_ring[cons];
357062306a36Sopenharmony_ci	data = rx_buf->data_ptr;
357162306a36Sopenharmony_ci	len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT;
357262306a36Sopenharmony_ci	if (len != pkt_size)
357362306a36Sopenharmony_ci		return -EIO;
357462306a36Sopenharmony_ci	i = ETH_ALEN;
357562306a36Sopenharmony_ci	if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr))
357662306a36Sopenharmony_ci		return -EIO;
357762306a36Sopenharmony_ci	i += ETH_ALEN;
357862306a36Sopenharmony_ci	for (  ; i < pkt_size; i++) {
357962306a36Sopenharmony_ci		if (data[i] != (u8)(i & 0xff))
358062306a36Sopenharmony_ci			return -EIO;
358162306a36Sopenharmony_ci	}
358262306a36Sopenharmony_ci	return 0;
358362306a36Sopenharmony_ci}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_cistatic int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
358662306a36Sopenharmony_ci			      int pkt_size)
358762306a36Sopenharmony_ci{
358862306a36Sopenharmony_ci	struct tx_cmp *txcmp;
358962306a36Sopenharmony_ci	int rc = -EIO;
359062306a36Sopenharmony_ci	u32 raw_cons;
359162306a36Sopenharmony_ci	u32 cons;
359262306a36Sopenharmony_ci	int i;
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	raw_cons = cpr->cp_raw_cons;
359562306a36Sopenharmony_ci	for (i = 0; i < 200; i++) {
359662306a36Sopenharmony_ci		cons = RING_CMP(raw_cons);
359762306a36Sopenharmony_ci		txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)];
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci		if (!TX_CMP_VALID(txcmp, raw_cons)) {
360062306a36Sopenharmony_ci			udelay(5);
360162306a36Sopenharmony_ci			continue;
360262306a36Sopenharmony_ci		}
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci		/* The valid test of the entry must be done first before
360562306a36Sopenharmony_ci		 * reading any further.
360662306a36Sopenharmony_ci		 */
360762306a36Sopenharmony_ci		dma_rmb();
360862306a36Sopenharmony_ci		if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) {
360962306a36Sopenharmony_ci			rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size);
361062306a36Sopenharmony_ci			raw_cons = NEXT_RAW_CMP(raw_cons);
361162306a36Sopenharmony_ci			raw_cons = NEXT_RAW_CMP(raw_cons);
361262306a36Sopenharmony_ci			break;
361362306a36Sopenharmony_ci		}
361462306a36Sopenharmony_ci		raw_cons = NEXT_RAW_CMP(raw_cons);
361562306a36Sopenharmony_ci	}
361662306a36Sopenharmony_ci	cpr->cp_raw_cons = raw_cons;
361762306a36Sopenharmony_ci	return rc;
361862306a36Sopenharmony_ci}
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_cistatic int bnxt_run_loopback(struct bnxt *bp)
362162306a36Sopenharmony_ci{
362262306a36Sopenharmony_ci	struct bnxt_tx_ring_info *txr = &bp->tx_ring[0];
362362306a36Sopenharmony_ci	struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
362462306a36Sopenharmony_ci	struct bnxt_cp_ring_info *cpr;
362562306a36Sopenharmony_ci	int pkt_size, i = 0;
362662306a36Sopenharmony_ci	struct sk_buff *skb;
362762306a36Sopenharmony_ci	dma_addr_t map;
362862306a36Sopenharmony_ci	u8 *data;
362962306a36Sopenharmony_ci	int rc;
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	cpr = &rxr->bnapi->cp_ring;
363262306a36Sopenharmony_ci	if (bp->flags & BNXT_FLAG_CHIP_P5)
363362306a36Sopenharmony_ci		cpr = cpr->cp_ring_arr[BNXT_RX_HDL];
363462306a36Sopenharmony_ci	pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh);
363562306a36Sopenharmony_ci	skb = netdev_alloc_skb(bp->dev, pkt_size);
363662306a36Sopenharmony_ci	if (!skb)
363762306a36Sopenharmony_ci		return -ENOMEM;
363862306a36Sopenharmony_ci	data = skb_put(skb, pkt_size);
363962306a36Sopenharmony_ci	ether_addr_copy(&data[i], bp->dev->dev_addr);
364062306a36Sopenharmony_ci	i += ETH_ALEN;
364162306a36Sopenharmony_ci	ether_addr_copy(&data[i], bp->dev->dev_addr);
364262306a36Sopenharmony_ci	i += ETH_ALEN;
364362306a36Sopenharmony_ci	for ( ; i < pkt_size; i++)
364462306a36Sopenharmony_ci		data[i] = (u8)(i & 0xff);
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
364762306a36Sopenharmony_ci			     DMA_TO_DEVICE);
364862306a36Sopenharmony_ci	if (dma_mapping_error(&bp->pdev->dev, map)) {
364962306a36Sopenharmony_ci		dev_kfree_skb(skb);
365062306a36Sopenharmony_ci		return -EIO;
365162306a36Sopenharmony_ci	}
365262306a36Sopenharmony_ci	bnxt_xmit_bd(bp, txr, map, pkt_size, NULL);
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_ci	/* Sync BD data before updating doorbell */
365562306a36Sopenharmony_ci	wmb();
365662306a36Sopenharmony_ci
365762306a36Sopenharmony_ci	bnxt_db_write(bp, &txr->tx_db, txr->tx_prod);
365862306a36Sopenharmony_ci	rc = bnxt_poll_loopback(bp, cpr, pkt_size);
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_ci	dma_unmap_single(&bp->pdev->dev, map, pkt_size, DMA_TO_DEVICE);
366162306a36Sopenharmony_ci	dev_kfree_skb(skb);
366262306a36Sopenharmony_ci	return rc;
366362306a36Sopenharmony_ci}
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_cistatic int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results)
366662306a36Sopenharmony_ci{
366762306a36Sopenharmony_ci	struct hwrm_selftest_exec_output *resp;
366862306a36Sopenharmony_ci	struct hwrm_selftest_exec_input *req;
366962306a36Sopenharmony_ci	int rc;
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci	rc = hwrm_req_init(bp, req, HWRM_SELFTEST_EXEC);
367262306a36Sopenharmony_ci	if (rc)
367362306a36Sopenharmony_ci		return rc;
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	hwrm_req_timeout(bp, req, bp->test_info->timeout);
367662306a36Sopenharmony_ci	req->flags = test_mask;
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci	resp = hwrm_req_hold(bp, req);
367962306a36Sopenharmony_ci	rc = hwrm_req_send(bp, req);
368062306a36Sopenharmony_ci	*test_results = resp->test_success;
368162306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
368262306a36Sopenharmony_ci	return rc;
368362306a36Sopenharmony_ci}
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci#define BNXT_DRV_TESTS			4
368662306a36Sopenharmony_ci#define BNXT_MACLPBK_TEST_IDX		(bp->num_tests - BNXT_DRV_TESTS)
368762306a36Sopenharmony_ci#define BNXT_PHYLPBK_TEST_IDX		(BNXT_MACLPBK_TEST_IDX + 1)
368862306a36Sopenharmony_ci#define BNXT_EXTLPBK_TEST_IDX		(BNXT_MACLPBK_TEST_IDX + 2)
368962306a36Sopenharmony_ci#define BNXT_IRQ_TEST_IDX		(BNXT_MACLPBK_TEST_IDX + 3)
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_cistatic void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
369262306a36Sopenharmony_ci			   u64 *buf)
369362306a36Sopenharmony_ci{
369462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
369562306a36Sopenharmony_ci	bool do_ext_lpbk = false;
369662306a36Sopenharmony_ci	bool offline = false;
369762306a36Sopenharmony_ci	u8 test_results = 0;
369862306a36Sopenharmony_ci	u8 test_mask = 0;
369962306a36Sopenharmony_ci	int rc = 0, i;
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	if (!bp->num_tests || !BNXT_PF(bp))
370262306a36Sopenharmony_ci		return;
370362306a36Sopenharmony_ci	memset(buf, 0, sizeof(u64) * bp->num_tests);
370462306a36Sopenharmony_ci	if (!netif_running(dev)) {
370562306a36Sopenharmony_ci		etest->flags |= ETH_TEST_FL_FAILED;
370662306a36Sopenharmony_ci		return;
370762306a36Sopenharmony_ci	}
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) &&
371062306a36Sopenharmony_ci	    (bp->phy_flags & BNXT_PHY_FL_EXT_LPBK))
371162306a36Sopenharmony_ci		do_ext_lpbk = true;
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci	if (etest->flags & ETH_TEST_FL_OFFLINE) {
371462306a36Sopenharmony_ci		if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) {
371562306a36Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
371662306a36Sopenharmony_ci			netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n");
371762306a36Sopenharmony_ci			return;
371862306a36Sopenharmony_ci		}
371962306a36Sopenharmony_ci		offline = true;
372062306a36Sopenharmony_ci	}
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) {
372362306a36Sopenharmony_ci		u8 bit_val = 1 << i;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci		if (!(bp->test_info->offline_mask & bit_val))
372662306a36Sopenharmony_ci			test_mask |= bit_val;
372762306a36Sopenharmony_ci		else if (offline)
372862306a36Sopenharmony_ci			test_mask |= bit_val;
372962306a36Sopenharmony_ci	}
373062306a36Sopenharmony_ci	if (!offline) {
373162306a36Sopenharmony_ci		bnxt_run_fw_tests(bp, test_mask, &test_results);
373262306a36Sopenharmony_ci	} else {
373362306a36Sopenharmony_ci		bnxt_ulp_stop(bp);
373462306a36Sopenharmony_ci		bnxt_close_nic(bp, true, false);
373562306a36Sopenharmony_ci		bnxt_run_fw_tests(bp, test_mask, &test_results);
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci		buf[BNXT_MACLPBK_TEST_IDX] = 1;
373862306a36Sopenharmony_ci		bnxt_hwrm_mac_loopback(bp, true);
373962306a36Sopenharmony_ci		msleep(250);
374062306a36Sopenharmony_ci		rc = bnxt_half_open_nic(bp);
374162306a36Sopenharmony_ci		if (rc) {
374262306a36Sopenharmony_ci			bnxt_hwrm_mac_loopback(bp, false);
374362306a36Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
374462306a36Sopenharmony_ci			bnxt_ulp_start(bp, rc);
374562306a36Sopenharmony_ci			return;
374662306a36Sopenharmony_ci		}
374762306a36Sopenharmony_ci		if (bnxt_run_loopback(bp))
374862306a36Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
374962306a36Sopenharmony_ci		else
375062306a36Sopenharmony_ci			buf[BNXT_MACLPBK_TEST_IDX] = 0;
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci		bnxt_hwrm_mac_loopback(bp, false);
375362306a36Sopenharmony_ci		bnxt_hwrm_phy_loopback(bp, true, false);
375462306a36Sopenharmony_ci		msleep(1000);
375562306a36Sopenharmony_ci		if (bnxt_run_loopback(bp)) {
375662306a36Sopenharmony_ci			buf[BNXT_PHYLPBK_TEST_IDX] = 1;
375762306a36Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
375862306a36Sopenharmony_ci		}
375962306a36Sopenharmony_ci		if (do_ext_lpbk) {
376062306a36Sopenharmony_ci			etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
376162306a36Sopenharmony_ci			bnxt_hwrm_phy_loopback(bp, true, true);
376262306a36Sopenharmony_ci			msleep(1000);
376362306a36Sopenharmony_ci			if (bnxt_run_loopback(bp)) {
376462306a36Sopenharmony_ci				buf[BNXT_EXTLPBK_TEST_IDX] = 1;
376562306a36Sopenharmony_ci				etest->flags |= ETH_TEST_FL_FAILED;
376662306a36Sopenharmony_ci			}
376762306a36Sopenharmony_ci		}
376862306a36Sopenharmony_ci		bnxt_hwrm_phy_loopback(bp, false, false);
376962306a36Sopenharmony_ci		bnxt_half_close_nic(bp);
377062306a36Sopenharmony_ci		rc = bnxt_open_nic(bp, true, true);
377162306a36Sopenharmony_ci		bnxt_ulp_start(bp, rc);
377262306a36Sopenharmony_ci	}
377362306a36Sopenharmony_ci	if (rc || bnxt_test_irq(bp)) {
377462306a36Sopenharmony_ci		buf[BNXT_IRQ_TEST_IDX] = 1;
377562306a36Sopenharmony_ci		etest->flags |= ETH_TEST_FL_FAILED;
377662306a36Sopenharmony_ci	}
377762306a36Sopenharmony_ci	for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) {
377862306a36Sopenharmony_ci		u8 bit_val = 1 << i;
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci		if ((test_mask & bit_val) && !(test_results & bit_val)) {
378162306a36Sopenharmony_ci			buf[i] = 1;
378262306a36Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
378362306a36Sopenharmony_ci		}
378462306a36Sopenharmony_ci	}
378562306a36Sopenharmony_ci}
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_cistatic int bnxt_reset(struct net_device *dev, u32 *flags)
378862306a36Sopenharmony_ci{
378962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
379062306a36Sopenharmony_ci	bool reload = false;
379162306a36Sopenharmony_ci	u32 req = *flags;
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	if (!req)
379462306a36Sopenharmony_ci		return -EINVAL;
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	if (!BNXT_PF(bp)) {
379762306a36Sopenharmony_ci		netdev_err(dev, "Reset is not supported from a VF\n");
379862306a36Sopenharmony_ci		return -EOPNOTSUPP;
379962306a36Sopenharmony_ci	}
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci	if (pci_vfs_assigned(bp->pdev) &&
380262306a36Sopenharmony_ci	    !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) {
380362306a36Sopenharmony_ci		netdev_err(dev,
380462306a36Sopenharmony_ci			   "Reset not allowed when VFs are assigned to VMs\n");
380562306a36Sopenharmony_ci		return -EBUSY;
380662306a36Sopenharmony_ci	}
380762306a36Sopenharmony_ci
380862306a36Sopenharmony_ci	if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) {
380962306a36Sopenharmony_ci		/* This feature is not supported in older firmware versions */
381062306a36Sopenharmony_ci		if (bp->hwrm_spec_code >= 0x10803) {
381162306a36Sopenharmony_ci			if (!bnxt_firmware_reset_chip(dev)) {
381262306a36Sopenharmony_ci				netdev_info(dev, "Firmware reset request successful.\n");
381362306a36Sopenharmony_ci				if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET))
381462306a36Sopenharmony_ci					reload = true;
381562306a36Sopenharmony_ci				*flags &= ~BNXT_FW_RESET_CHIP;
381662306a36Sopenharmony_ci			}
381762306a36Sopenharmony_ci		} else if (req == BNXT_FW_RESET_CHIP) {
381862306a36Sopenharmony_ci			return -EOPNOTSUPP; /* only request, fail hard */
381962306a36Sopenharmony_ci		}
382062306a36Sopenharmony_ci	}
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) {
382362306a36Sopenharmony_ci		/* This feature is not supported in older firmware versions */
382462306a36Sopenharmony_ci		if (bp->hwrm_spec_code >= 0x10803) {
382562306a36Sopenharmony_ci			if (!bnxt_firmware_reset_ap(dev)) {
382662306a36Sopenharmony_ci				netdev_info(dev, "Reset application processor successful.\n");
382762306a36Sopenharmony_ci				reload = true;
382862306a36Sopenharmony_ci				*flags &= ~BNXT_FW_RESET_AP;
382962306a36Sopenharmony_ci			}
383062306a36Sopenharmony_ci		} else if (req == BNXT_FW_RESET_AP) {
383162306a36Sopenharmony_ci			return -EOPNOTSUPP; /* only request, fail hard */
383262306a36Sopenharmony_ci		}
383362306a36Sopenharmony_ci	}
383462306a36Sopenharmony_ci
383562306a36Sopenharmony_ci	if (reload)
383662306a36Sopenharmony_ci		netdev_info(dev, "Reload driver to complete reset\n");
383762306a36Sopenharmony_ci
383862306a36Sopenharmony_ci	return 0;
383962306a36Sopenharmony_ci}
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_cistatic int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump)
384262306a36Sopenharmony_ci{
384362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	if (dump->flag > BNXT_DUMP_CRASH) {
384662306a36Sopenharmony_ci		netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n");
384762306a36Sopenharmony_ci		return -EINVAL;
384862306a36Sopenharmony_ci	}
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) {
385162306a36Sopenharmony_ci		netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n");
385262306a36Sopenharmony_ci		return -EOPNOTSUPP;
385362306a36Sopenharmony_ci	}
385462306a36Sopenharmony_ci
385562306a36Sopenharmony_ci	bp->dump_flag = dump->flag;
385662306a36Sopenharmony_ci	return 0;
385762306a36Sopenharmony_ci}
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_cistatic int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
386062306a36Sopenharmony_ci{
386162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10801)
386462306a36Sopenharmony_ci		return -EOPNOTSUPP;
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci	dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 |
386762306a36Sopenharmony_ci			bp->ver_resp.hwrm_fw_min_8b << 16 |
386862306a36Sopenharmony_ci			bp->ver_resp.hwrm_fw_bld_8b << 8 |
386962306a36Sopenharmony_ci			bp->ver_resp.hwrm_fw_rsvd_8b;
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	dump->flag = bp->dump_flag;
387262306a36Sopenharmony_ci	dump->len = bnxt_get_coredump_length(bp, bp->dump_flag);
387362306a36Sopenharmony_ci	return 0;
387462306a36Sopenharmony_ci}
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_cistatic int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
387762306a36Sopenharmony_ci			      void *buf)
387862306a36Sopenharmony_ci{
387962306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10801)
388262306a36Sopenharmony_ci		return -EOPNOTSUPP;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	memset(buf, 0, dump->len);
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci	dump->flag = bp->dump_flag;
388762306a36Sopenharmony_ci	return bnxt_get_coredump(bp, dump->flag, buf, &dump->len);
388862306a36Sopenharmony_ci}
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_cistatic int bnxt_get_ts_info(struct net_device *dev,
389162306a36Sopenharmony_ci			    struct ethtool_ts_info *info)
389262306a36Sopenharmony_ci{
389362306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
389462306a36Sopenharmony_ci	struct bnxt_ptp_cfg *ptp;
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci	ptp = bp->ptp_cfg;
389762306a36Sopenharmony_ci	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
389862306a36Sopenharmony_ci				SOF_TIMESTAMPING_RX_SOFTWARE |
389962306a36Sopenharmony_ci				SOF_TIMESTAMPING_SOFTWARE;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	info->phc_index = -1;
390262306a36Sopenharmony_ci	if (!ptp)
390362306a36Sopenharmony_ci		return 0;
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
390662306a36Sopenharmony_ci				 SOF_TIMESTAMPING_RX_HARDWARE |
390762306a36Sopenharmony_ci				 SOF_TIMESTAMPING_RAW_HARDWARE;
390862306a36Sopenharmony_ci	if (ptp->ptp_clock)
390962306a36Sopenharmony_ci		info->phc_index = ptp_clock_index(ptp->ptp_clock);
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_ci	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
391462306a36Sopenharmony_ci			   (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
391562306a36Sopenharmony_ci			   (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci	if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS)
391862306a36Sopenharmony_ci		info->rx_filters |= (1 << HWTSTAMP_FILTER_ALL);
391962306a36Sopenharmony_ci	return 0;
392062306a36Sopenharmony_ci}
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_civoid bnxt_ethtool_init(struct bnxt *bp)
392362306a36Sopenharmony_ci{
392462306a36Sopenharmony_ci	struct hwrm_selftest_qlist_output *resp;
392562306a36Sopenharmony_ci	struct hwrm_selftest_qlist_input *req;
392662306a36Sopenharmony_ci	struct bnxt_test_info *test_info;
392762306a36Sopenharmony_ci	struct net_device *dev = bp->dev;
392862306a36Sopenharmony_ci	int i, rc;
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_ci	if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER))
393162306a36Sopenharmony_ci		bnxt_get_pkgver(dev);
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci	bp->num_tests = 0;
393462306a36Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp))
393562306a36Sopenharmony_ci		return;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci	test_info = bp->test_info;
393862306a36Sopenharmony_ci	if (!test_info) {
393962306a36Sopenharmony_ci		test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL);
394062306a36Sopenharmony_ci		if (!test_info)
394162306a36Sopenharmony_ci			return;
394262306a36Sopenharmony_ci		bp->test_info = test_info;
394362306a36Sopenharmony_ci	}
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci	if (hwrm_req_init(bp, req, HWRM_SELFTEST_QLIST))
394662306a36Sopenharmony_ci		return;
394762306a36Sopenharmony_ci
394862306a36Sopenharmony_ci	resp = hwrm_req_hold(bp, req);
394962306a36Sopenharmony_ci	rc = hwrm_req_send_silent(bp, req);
395062306a36Sopenharmony_ci	if (rc)
395162306a36Sopenharmony_ci		goto ethtool_init_exit;
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_ci	bp->num_tests = resp->num_tests + BNXT_DRV_TESTS;
395462306a36Sopenharmony_ci	if (bp->num_tests > BNXT_MAX_TEST)
395562306a36Sopenharmony_ci		bp->num_tests = BNXT_MAX_TEST;
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci	test_info->offline_mask = resp->offline_tests;
395862306a36Sopenharmony_ci	test_info->timeout = le16_to_cpu(resp->test_timeout);
395962306a36Sopenharmony_ci	if (!test_info->timeout)
396062306a36Sopenharmony_ci		test_info->timeout = HWRM_CMD_TIMEOUT;
396162306a36Sopenharmony_ci	for (i = 0; i < bp->num_tests; i++) {
396262306a36Sopenharmony_ci		char *str = test_info->string[i];
396362306a36Sopenharmony_ci		char *fw_str = resp->test_name[i];
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci		if (i == BNXT_MACLPBK_TEST_IDX) {
396662306a36Sopenharmony_ci			strcpy(str, "Mac loopback test (offline)");
396762306a36Sopenharmony_ci		} else if (i == BNXT_PHYLPBK_TEST_IDX) {
396862306a36Sopenharmony_ci			strcpy(str, "Phy loopback test (offline)");
396962306a36Sopenharmony_ci		} else if (i == BNXT_EXTLPBK_TEST_IDX) {
397062306a36Sopenharmony_ci			strcpy(str, "Ext loopback test (offline)");
397162306a36Sopenharmony_ci		} else if (i == BNXT_IRQ_TEST_IDX) {
397262306a36Sopenharmony_ci			strcpy(str, "Interrupt_test (offline)");
397362306a36Sopenharmony_ci		} else {
397462306a36Sopenharmony_ci			snprintf(str, ETH_GSTRING_LEN, "%s test (%s)",
397562306a36Sopenharmony_ci				 fw_str, test_info->offline_mask & (1 << i) ?
397662306a36Sopenharmony_ci					"offline" : "online");
397762306a36Sopenharmony_ci		}
397862306a36Sopenharmony_ci	}
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ciethtool_init_exit:
398162306a36Sopenharmony_ci	hwrm_req_drop(bp, req);
398262306a36Sopenharmony_ci}
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_cistatic void bnxt_get_eth_phy_stats(struct net_device *dev,
398562306a36Sopenharmony_ci				   struct ethtool_eth_phy_stats *phy_stats)
398662306a36Sopenharmony_ci{
398762306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
398862306a36Sopenharmony_ci	u64 *rx;
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT))
399162306a36Sopenharmony_ci		return;
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	rx = bp->rx_port_stats_ext.sw_stats;
399462306a36Sopenharmony_ci	phy_stats->SymbolErrorDuringCarrier =
399562306a36Sopenharmony_ci		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err));
399662306a36Sopenharmony_ci}
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_cistatic void bnxt_get_eth_mac_stats(struct net_device *dev,
399962306a36Sopenharmony_ci				   struct ethtool_eth_mac_stats *mac_stats)
400062306a36Sopenharmony_ci{
400162306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
400262306a36Sopenharmony_ci	u64 *rx, *tx;
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
400562306a36Sopenharmony_ci		return;
400662306a36Sopenharmony_ci
400762306a36Sopenharmony_ci	rx = bp->port_stats.sw_stats;
400862306a36Sopenharmony_ci	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ci	mac_stats->FramesReceivedOK =
401162306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames);
401262306a36Sopenharmony_ci	mac_stats->FramesTransmittedOK =
401362306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames);
401462306a36Sopenharmony_ci	mac_stats->FrameCheckSequenceErrors =
401562306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_fcs_err_frames);
401662306a36Sopenharmony_ci	mac_stats->AlignmentErrors =
401762306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_align_err_frames);
401862306a36Sopenharmony_ci	mac_stats->OutOfRangeLengthField =
401962306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_oor_len_frames);
402062306a36Sopenharmony_ci}
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_cistatic void bnxt_get_eth_ctrl_stats(struct net_device *dev,
402362306a36Sopenharmony_ci				    struct ethtool_eth_ctrl_stats *ctrl_stats)
402462306a36Sopenharmony_ci{
402562306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
402662306a36Sopenharmony_ci	u64 *rx;
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
402962306a36Sopenharmony_ci		return;
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_ci	rx = bp->port_stats.sw_stats;
403262306a36Sopenharmony_ci	ctrl_stats->MACControlFramesReceived =
403362306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames);
403462306a36Sopenharmony_ci}
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_cistatic const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = {
403762306a36Sopenharmony_ci	{    0,    64 },
403862306a36Sopenharmony_ci	{   65,   127 },
403962306a36Sopenharmony_ci	{  128,   255 },
404062306a36Sopenharmony_ci	{  256,   511 },
404162306a36Sopenharmony_ci	{  512,  1023 },
404262306a36Sopenharmony_ci	{ 1024,  1518 },
404362306a36Sopenharmony_ci	{ 1519,  2047 },
404462306a36Sopenharmony_ci	{ 2048,  4095 },
404562306a36Sopenharmony_ci	{ 4096,  9216 },
404662306a36Sopenharmony_ci	{ 9217, 16383 },
404762306a36Sopenharmony_ci	{}
404862306a36Sopenharmony_ci};
404962306a36Sopenharmony_ci
405062306a36Sopenharmony_cistatic void bnxt_get_rmon_stats(struct net_device *dev,
405162306a36Sopenharmony_ci				struct ethtool_rmon_stats *rmon_stats,
405262306a36Sopenharmony_ci				const struct ethtool_rmon_hist_range **ranges)
405362306a36Sopenharmony_ci{
405462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
405562306a36Sopenharmony_ci	u64 *rx, *tx;
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
405862306a36Sopenharmony_ci		return;
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	rx = bp->port_stats.sw_stats;
406162306a36Sopenharmony_ci	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci	rmon_stats->jabbers =
406462306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames);
406562306a36Sopenharmony_ci	rmon_stats->oversize_pkts =
406662306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames);
406762306a36Sopenharmony_ci	rmon_stats->undersize_pkts =
406862306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames);
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci	rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames);
407162306a36Sopenharmony_ci	rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames);
407262306a36Sopenharmony_ci	rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames);
407362306a36Sopenharmony_ci	rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames);
407462306a36Sopenharmony_ci	rmon_stats->hist[4] =
407562306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames);
407662306a36Sopenharmony_ci	rmon_stats->hist[5] =
407762306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames);
407862306a36Sopenharmony_ci	rmon_stats->hist[6] =
407962306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames);
408062306a36Sopenharmony_ci	rmon_stats->hist[7] =
408162306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames);
408262306a36Sopenharmony_ci	rmon_stats->hist[8] =
408362306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames);
408462306a36Sopenharmony_ci	rmon_stats->hist[9] =
408562306a36Sopenharmony_ci		BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames);
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci	rmon_stats->hist_tx[0] =
408862306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames);
408962306a36Sopenharmony_ci	rmon_stats->hist_tx[1] =
409062306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames);
409162306a36Sopenharmony_ci	rmon_stats->hist_tx[2] =
409262306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames);
409362306a36Sopenharmony_ci	rmon_stats->hist_tx[3] =
409462306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames);
409562306a36Sopenharmony_ci	rmon_stats->hist_tx[4] =
409662306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames);
409762306a36Sopenharmony_ci	rmon_stats->hist_tx[5] =
409862306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames);
409962306a36Sopenharmony_ci	rmon_stats->hist_tx[6] =
410062306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames);
410162306a36Sopenharmony_ci	rmon_stats->hist_tx[7] =
410262306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames);
410362306a36Sopenharmony_ci	rmon_stats->hist_tx[8] =
410462306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames);
410562306a36Sopenharmony_ci	rmon_stats->hist_tx[9] =
410662306a36Sopenharmony_ci		BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames);
410762306a36Sopenharmony_ci
410862306a36Sopenharmony_ci	*ranges = bnxt_rmon_ranges;
410962306a36Sopenharmony_ci}
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_cistatic void bnxt_get_link_ext_stats(struct net_device *dev,
411262306a36Sopenharmony_ci				    struct ethtool_link_ext_stats *stats)
411362306a36Sopenharmony_ci{
411462306a36Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
411562306a36Sopenharmony_ci	u64 *rx;
411662306a36Sopenharmony_ci
411762306a36Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT))
411862306a36Sopenharmony_ci		return;
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci	rx = bp->rx_port_stats_ext.sw_stats;
412162306a36Sopenharmony_ci	stats->link_down_events =
412262306a36Sopenharmony_ci		*(rx + BNXT_RX_STATS_EXT_OFFSET(link_down_events));
412362306a36Sopenharmony_ci}
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_civoid bnxt_ethtool_free(struct bnxt *bp)
412662306a36Sopenharmony_ci{
412762306a36Sopenharmony_ci	kfree(bp->test_info);
412862306a36Sopenharmony_ci	bp->test_info = NULL;
412962306a36Sopenharmony_ci}
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ciconst struct ethtool_ops bnxt_ethtool_ops = {
413262306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
413362306a36Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES |
413462306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USECS_IRQ |
413562306a36Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES_IRQ |
413662306a36Sopenharmony_ci				     ETHTOOL_COALESCE_STATS_BLOCK_USECS |
413762306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX |
413862306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USE_CQE,
413962306a36Sopenharmony_ci	.get_link_ksettings	= bnxt_get_link_ksettings,
414062306a36Sopenharmony_ci	.set_link_ksettings	= bnxt_set_link_ksettings,
414162306a36Sopenharmony_ci	.get_fec_stats		= bnxt_get_fec_stats,
414262306a36Sopenharmony_ci	.get_fecparam		= bnxt_get_fecparam,
414362306a36Sopenharmony_ci	.set_fecparam		= bnxt_set_fecparam,
414462306a36Sopenharmony_ci	.get_pause_stats	= bnxt_get_pause_stats,
414562306a36Sopenharmony_ci	.get_pauseparam		= bnxt_get_pauseparam,
414662306a36Sopenharmony_ci	.set_pauseparam		= bnxt_set_pauseparam,
414762306a36Sopenharmony_ci	.get_drvinfo		= bnxt_get_drvinfo,
414862306a36Sopenharmony_ci	.get_regs_len		= bnxt_get_regs_len,
414962306a36Sopenharmony_ci	.get_regs		= bnxt_get_regs,
415062306a36Sopenharmony_ci	.get_wol		= bnxt_get_wol,
415162306a36Sopenharmony_ci	.set_wol		= bnxt_set_wol,
415262306a36Sopenharmony_ci	.get_coalesce		= bnxt_get_coalesce,
415362306a36Sopenharmony_ci	.set_coalesce		= bnxt_set_coalesce,
415462306a36Sopenharmony_ci	.get_msglevel		= bnxt_get_msglevel,
415562306a36Sopenharmony_ci	.set_msglevel		= bnxt_set_msglevel,
415662306a36Sopenharmony_ci	.get_sset_count		= bnxt_get_sset_count,
415762306a36Sopenharmony_ci	.get_strings		= bnxt_get_strings,
415862306a36Sopenharmony_ci	.get_ethtool_stats	= bnxt_get_ethtool_stats,
415962306a36Sopenharmony_ci	.set_ringparam		= bnxt_set_ringparam,
416062306a36Sopenharmony_ci	.get_ringparam		= bnxt_get_ringparam,
416162306a36Sopenharmony_ci	.get_channels		= bnxt_get_channels,
416262306a36Sopenharmony_ci	.set_channels		= bnxt_set_channels,
416362306a36Sopenharmony_ci	.get_rxnfc		= bnxt_get_rxnfc,
416462306a36Sopenharmony_ci	.set_rxnfc		= bnxt_set_rxnfc,
416562306a36Sopenharmony_ci	.get_rxfh_indir_size    = bnxt_get_rxfh_indir_size,
416662306a36Sopenharmony_ci	.get_rxfh_key_size      = bnxt_get_rxfh_key_size,
416762306a36Sopenharmony_ci	.get_rxfh               = bnxt_get_rxfh,
416862306a36Sopenharmony_ci	.set_rxfh		= bnxt_set_rxfh,
416962306a36Sopenharmony_ci	.flash_device		= bnxt_flash_device,
417062306a36Sopenharmony_ci	.get_eeprom_len         = bnxt_get_eeprom_len,
417162306a36Sopenharmony_ci	.get_eeprom             = bnxt_get_eeprom,
417262306a36Sopenharmony_ci	.set_eeprom		= bnxt_set_eeprom,
417362306a36Sopenharmony_ci	.get_link		= bnxt_get_link,
417462306a36Sopenharmony_ci	.get_link_ext_stats	= bnxt_get_link_ext_stats,
417562306a36Sopenharmony_ci	.get_eee		= bnxt_get_eee,
417662306a36Sopenharmony_ci	.set_eee		= bnxt_set_eee,
417762306a36Sopenharmony_ci	.get_module_info	= bnxt_get_module_info,
417862306a36Sopenharmony_ci	.get_module_eeprom	= bnxt_get_module_eeprom,
417962306a36Sopenharmony_ci	.get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page,
418062306a36Sopenharmony_ci	.nway_reset		= bnxt_nway_reset,
418162306a36Sopenharmony_ci	.set_phys_id		= bnxt_set_phys_id,
418262306a36Sopenharmony_ci	.self_test		= bnxt_self_test,
418362306a36Sopenharmony_ci	.get_ts_info		= bnxt_get_ts_info,
418462306a36Sopenharmony_ci	.reset			= bnxt_reset,
418562306a36Sopenharmony_ci	.set_dump		= bnxt_set_dump,
418662306a36Sopenharmony_ci	.get_dump_flag		= bnxt_get_dump_flag,
418762306a36Sopenharmony_ci	.get_dump_data		= bnxt_get_dump_data,
418862306a36Sopenharmony_ci	.get_eth_phy_stats	= bnxt_get_eth_phy_stats,
418962306a36Sopenharmony_ci	.get_eth_mac_stats	= bnxt_get_eth_mac_stats,
419062306a36Sopenharmony_ci	.get_eth_ctrl_stats	= bnxt_get_eth_ctrl_stats,
419162306a36Sopenharmony_ci	.get_rmon_stats		= bnxt_get_rmon_stats,
419262306a36Sopenharmony_ci};
4193