18c2ecf20Sopenharmony_ci/* Broadcom NetXtreme-C/E network driver.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 Broadcom Corporation
48c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Broadcom Limited
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
88c2ecf20Sopenharmony_ci * the Free Software Foundation.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/ctype.h>
128c2ecf20Sopenharmony_ci#include <linux/stringify.h>
138c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
148c2ecf20Sopenharmony_ci#include <linux/linkmode.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/pci.h>
178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/crc32.h>
198c2ecf20Sopenharmony_ci#include <linux/firmware.h>
208c2ecf20Sopenharmony_ci#include <linux/utsname.h>
218c2ecf20Sopenharmony_ci#include <linux/time.h>
228c2ecf20Sopenharmony_ci#include "bnxt_hsi.h"
238c2ecf20Sopenharmony_ci#include "bnxt.h"
248c2ecf20Sopenharmony_ci#include "bnxt_xdp.h"
258c2ecf20Sopenharmony_ci#include "bnxt_ethtool.h"
268c2ecf20Sopenharmony_ci#include "bnxt_nvm_defs.h"	/* NVRAM content constant and structure defs */
278c2ecf20Sopenharmony_ci#include "bnxt_fw_hdr.h"	/* Firmware hdr constant and structure defs */
288c2ecf20Sopenharmony_ci#include "bnxt_coredump.h"
298c2ecf20Sopenharmony_ci#define FLASH_NVRAM_TIMEOUT	((HWRM_CMD_TIMEOUT) * 100)
308c2ecf20Sopenharmony_ci#define FLASH_PACKAGE_TIMEOUT	((HWRM_CMD_TIMEOUT) * 200)
318c2ecf20Sopenharmony_ci#define INSTALL_PACKAGE_TIMEOUT	((HWRM_CMD_TIMEOUT) * 200)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic u32 bnxt_get_msglevel(struct net_device *dev)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return bp->msg_enable;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic void bnxt_set_msglevel(struct net_device *dev, u32 value)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	bp->msg_enable = value;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int bnxt_get_coalesce(struct net_device *dev,
488c2ecf20Sopenharmony_ci			     struct ethtool_coalesce *coal)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
518c2ecf20Sopenharmony_ci	struct bnxt_coal *hw_coal;
528c2ecf20Sopenharmony_ci	u16 mult;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	memset(coal, 0, sizeof(*coal));
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	coal->use_adaptive_rx_coalesce = bp->flags & BNXT_FLAG_DIM;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	hw_coal = &bp->rx_coal;
598c2ecf20Sopenharmony_ci	mult = hw_coal->bufs_per_record;
608c2ecf20Sopenharmony_ci	coal->rx_coalesce_usecs = hw_coal->coal_ticks;
618c2ecf20Sopenharmony_ci	coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult;
628c2ecf20Sopenharmony_ci	coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq;
638c2ecf20Sopenharmony_ci	coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	hw_coal = &bp->tx_coal;
668c2ecf20Sopenharmony_ci	mult = hw_coal->bufs_per_record;
678c2ecf20Sopenharmony_ci	coal->tx_coalesce_usecs = hw_coal->coal_ticks;
688c2ecf20Sopenharmony_ci	coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult;
698c2ecf20Sopenharmony_ci	coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq;
708c2ecf20Sopenharmony_ci	coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	coal->stats_block_coalesce_usecs = bp->stats_coal_ticks;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int bnxt_set_coalesce(struct net_device *dev,
788c2ecf20Sopenharmony_ci			     struct ethtool_coalesce *coal)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
818c2ecf20Sopenharmony_ci	bool update_stats = false;
828c2ecf20Sopenharmony_ci	struct bnxt_coal *hw_coal;
838c2ecf20Sopenharmony_ci	int rc = 0;
848c2ecf20Sopenharmony_ci	u16 mult;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (coal->use_adaptive_rx_coalesce) {
878c2ecf20Sopenharmony_ci		bp->flags |= BNXT_FLAG_DIM;
888c2ecf20Sopenharmony_ci	} else {
898c2ecf20Sopenharmony_ci		if (bp->flags & BNXT_FLAG_DIM) {
908c2ecf20Sopenharmony_ci			bp->flags &= ~(BNXT_FLAG_DIM);
918c2ecf20Sopenharmony_ci			goto reset_coalesce;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	hw_coal = &bp->rx_coal;
968c2ecf20Sopenharmony_ci	mult = hw_coal->bufs_per_record;
978c2ecf20Sopenharmony_ci	hw_coal->coal_ticks = coal->rx_coalesce_usecs;
988c2ecf20Sopenharmony_ci	hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult;
998c2ecf20Sopenharmony_ci	hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq;
1008c2ecf20Sopenharmony_ci	hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	hw_coal = &bp->tx_coal;
1038c2ecf20Sopenharmony_ci	mult = hw_coal->bufs_per_record;
1048c2ecf20Sopenharmony_ci	hw_coal->coal_ticks = coal->tx_coalesce_usecs;
1058c2ecf20Sopenharmony_ci	hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult;
1068c2ecf20Sopenharmony_ci	hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq;
1078c2ecf20Sopenharmony_ci	hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) {
1108c2ecf20Sopenharmony_ci		u32 stats_ticks = coal->stats_block_coalesce_usecs;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		/* Allow 0, which means disable. */
1138c2ecf20Sopenharmony_ci		if (stats_ticks)
1148c2ecf20Sopenharmony_ci			stats_ticks = clamp_t(u32, stats_ticks,
1158c2ecf20Sopenharmony_ci					      BNXT_MIN_STATS_COAL_TICKS,
1168c2ecf20Sopenharmony_ci					      BNXT_MAX_STATS_COAL_TICKS);
1178c2ecf20Sopenharmony_ci		stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS);
1188c2ecf20Sopenharmony_ci		bp->stats_coal_ticks = stats_ticks;
1198c2ecf20Sopenharmony_ci		if (bp->stats_coal_ticks)
1208c2ecf20Sopenharmony_ci			bp->current_interval =
1218c2ecf20Sopenharmony_ci				bp->stats_coal_ticks * HZ / 1000000;
1228c2ecf20Sopenharmony_ci		else
1238c2ecf20Sopenharmony_ci			bp->current_interval = BNXT_TIMER_INTERVAL;
1248c2ecf20Sopenharmony_ci		update_stats = true;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cireset_coalesce:
1288c2ecf20Sopenharmony_ci	if (test_bit(BNXT_STATE_OPEN, &bp->state)) {
1298c2ecf20Sopenharmony_ci		if (update_stats) {
1308c2ecf20Sopenharmony_ci			rc = bnxt_close_nic(bp, true, false);
1318c2ecf20Sopenharmony_ci			if (!rc)
1328c2ecf20Sopenharmony_ci				rc = bnxt_open_nic(bp, true, false);
1338c2ecf20Sopenharmony_ci		} else {
1348c2ecf20Sopenharmony_ci			rc = bnxt_hwrm_set_coal(bp);
1358c2ecf20Sopenharmony_ci		}
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return rc;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_rx_stats_str[] = {
1428c2ecf20Sopenharmony_ci	"rx_ucast_packets",
1438c2ecf20Sopenharmony_ci	"rx_mcast_packets",
1448c2ecf20Sopenharmony_ci	"rx_bcast_packets",
1458c2ecf20Sopenharmony_ci	"rx_discards",
1468c2ecf20Sopenharmony_ci	"rx_errors",
1478c2ecf20Sopenharmony_ci	"rx_ucast_bytes",
1488c2ecf20Sopenharmony_ci	"rx_mcast_bytes",
1498c2ecf20Sopenharmony_ci	"rx_bcast_bytes",
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_tx_stats_str[] = {
1538c2ecf20Sopenharmony_ci	"tx_ucast_packets",
1548c2ecf20Sopenharmony_ci	"tx_mcast_packets",
1558c2ecf20Sopenharmony_ci	"tx_bcast_packets",
1568c2ecf20Sopenharmony_ci	"tx_errors",
1578c2ecf20Sopenharmony_ci	"tx_discards",
1588c2ecf20Sopenharmony_ci	"tx_ucast_bytes",
1598c2ecf20Sopenharmony_ci	"tx_mcast_bytes",
1608c2ecf20Sopenharmony_ci	"tx_bcast_bytes",
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_tpa_stats_str[] = {
1648c2ecf20Sopenharmony_ci	"tpa_packets",
1658c2ecf20Sopenharmony_ci	"tpa_bytes",
1668c2ecf20Sopenharmony_ci	"tpa_events",
1678c2ecf20Sopenharmony_ci	"tpa_aborts",
1688c2ecf20Sopenharmony_ci};
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic const char * const bnxt_ring_tpa2_stats_str[] = {
1718c2ecf20Sopenharmony_ci	"rx_tpa_eligible_pkt",
1728c2ecf20Sopenharmony_ci	"rx_tpa_eligible_bytes",
1738c2ecf20Sopenharmony_ci	"rx_tpa_pkt",
1748c2ecf20Sopenharmony_ci	"rx_tpa_bytes",
1758c2ecf20Sopenharmony_ci	"rx_tpa_errors",
1768c2ecf20Sopenharmony_ci	"rx_tpa_events",
1778c2ecf20Sopenharmony_ci};
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic const char * const bnxt_rx_sw_stats_str[] = {
1808c2ecf20Sopenharmony_ci	"rx_l4_csum_errors",
1818c2ecf20Sopenharmony_ci	"rx_resets",
1828c2ecf20Sopenharmony_ci	"rx_buf_errors",
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic const char * const bnxt_cmn_sw_stats_str[] = {
1868c2ecf20Sopenharmony_ci	"missed_irqs",
1878c2ecf20Sopenharmony_ci};
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_ENTRY(counter)	\
1908c2ecf20Sopenharmony_ci	{ BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_ENTRY(counter)	\
1938c2ecf20Sopenharmony_ci	{ BNXT_TX_STATS_OFFSET(counter), __stringify(counter) }
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_ENTRY(counter)	\
1968c2ecf20Sopenharmony_ci	{ BNXT_RX_STATS_EXT_OFFSET(counter), __stringify(counter) }
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_ENTRY(counter)	\
1998c2ecf20Sopenharmony_ci	{ BNXT_TX_STATS_EXT_OFFSET(counter), __stringify(counter) }
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRY(n)				\
2028c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_duration_us),	\
2038c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(pfc_pri##n##_rx_transitions)
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRY(n)				\
2068c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_duration_us),	\
2078c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(pfc_pri##n##_tx_transitions)
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_PFC_ENTRIES				\
2108c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(0),				\
2118c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(1),				\
2128c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(2),				\
2138c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(3),				\
2148c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(4),				\
2158c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(5),				\
2168c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(6),				\
2178c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRY(7)
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_PFC_ENTRIES				\
2208c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(0),				\
2218c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(1),				\
2228c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(2),				\
2238c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(3),				\
2248c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(4),				\
2258c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(5),				\
2268c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(6),				\
2278c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRY(7)
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRY(n)				\
2308c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_bytes_cos##n),		\
2318c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_packets_cos##n)
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRY(n)				\
2348c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(tx_bytes_cos##n),		\
2358c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_ENTRY(tx_packets_cos##n)
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_COS_ENTRIES				\
2388c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(0),				\
2398c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(1),				\
2408c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(2),				\
2418c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(3),				\
2428c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(4),				\
2438c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(5),				\
2448c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(6),				\
2458c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRY(7)				\
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_EXT_COS_ENTRIES				\
2488c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(0),				\
2498c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(1),				\
2508c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(2),				\
2518c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(3),				\
2528c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(4),				\
2538c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(5),				\
2548c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(6),				\
2558c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRY(7)				\
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(n)			\
2588c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_discard_bytes_cos##n),	\
2598c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_discard_packets_cos##n)
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES				\
2628c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(0),				\
2638c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(1),				\
2648c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(2),				\
2658c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(3),				\
2668c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(4),				\
2678c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(5),				\
2688c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(6),				\
2698c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRY(7)
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRY(counter, n)		\
2728c2ecf20Sopenharmony_ci	{ BNXT_RX_STATS_EXT_OFFSET(counter##_cos0),	\
2738c2ecf20Sopenharmony_ci	  __stringify(counter##_pri##n) }
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRY(counter, n)		\
2768c2ecf20Sopenharmony_ci	{ BNXT_TX_STATS_EXT_OFFSET(counter##_cos0),	\
2778c2ecf20Sopenharmony_ci	  __stringify(counter##_pri##n) }
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci#define BNXT_RX_STATS_PRI_ENTRIES(counter)		\
2808c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 0),		\
2818c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 1),		\
2828c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 2),		\
2838c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 3),		\
2848c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 4),		\
2858c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 5),		\
2868c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 6),		\
2878c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRY(counter, 7)
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci#define BNXT_TX_STATS_PRI_ENTRIES(counter)		\
2908c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 0),		\
2918c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 1),		\
2928c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 2),		\
2938c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 3),		\
2948c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 4),		\
2958c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 5),		\
2968c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 6),		\
2978c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRY(counter, 7)
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cienum {
3008c2ecf20Sopenharmony_ci	RX_TOTAL_DISCARDS,
3018c2ecf20Sopenharmony_ci	TX_TOTAL_DISCARDS,
3028c2ecf20Sopenharmony_ci};
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic struct {
3058c2ecf20Sopenharmony_ci	u64			counter;
3068c2ecf20Sopenharmony_ci	char			string[ETH_GSTRING_LEN];
3078c2ecf20Sopenharmony_ci} bnxt_sw_func_stats[] = {
3088c2ecf20Sopenharmony_ci	{0, "rx_total_discard_pkts"},
3098c2ecf20Sopenharmony_ci	{0, "tx_total_discard_pkts"},
3108c2ecf20Sopenharmony_ci};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci#define NUM_RING_RX_SW_STATS		ARRAY_SIZE(bnxt_rx_sw_stats_str)
3138c2ecf20Sopenharmony_ci#define NUM_RING_CMN_SW_STATS		ARRAY_SIZE(bnxt_cmn_sw_stats_str)
3148c2ecf20Sopenharmony_ci#define NUM_RING_RX_HW_STATS		ARRAY_SIZE(bnxt_ring_rx_stats_str)
3158c2ecf20Sopenharmony_ci#define NUM_RING_TX_HW_STATS		ARRAY_SIZE(bnxt_ring_tx_stats_str)
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic const struct {
3188c2ecf20Sopenharmony_ci	long offset;
3198c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
3208c2ecf20Sopenharmony_ci} bnxt_port_stats_arr[] = {
3218c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_64b_frames),
3228c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_65b_127b_frames),
3238c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_128b_255b_frames),
3248c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_256b_511b_frames),
3258c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames),
3268c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_1024b_1518b_frames),
3278c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_good_vlan_frames),
3288c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames),
3298c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames),
3308c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames),
3318c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames),
3328c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_total_frames),
3338c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_ucast_frames),
3348c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_mcast_frames),
3358c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_bcast_frames),
3368c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_fcs_err_frames),
3378c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_ctrl_frames),
3388c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pause_frames),
3398c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_frames),
3408c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_align_err_frames),
3418c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_ovrsz_frames),
3428c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_jbr_frames),
3438c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_mtu_err_frames),
3448c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_tagged_frames),
3458c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_double_tagged_frames),
3468c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_good_frames),
3478c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0),
3488c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1),
3498c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2),
3508c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3),
3518c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4),
3528c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5),
3538c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6),
3548c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7),
3558c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_undrsz_frames),
3568c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_eee_lpi_events),
3578c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration),
3588c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_bytes),
3598c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_runt_bytes),
3608c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_runt_frames),
3618c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_stat_discard),
3628c2ecf20Sopenharmony_ci	BNXT_RX_STATS_ENTRY(rx_stat_err),
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_64b_frames),
3658c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_65b_127b_frames),
3668c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_128b_255b_frames),
3678c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_256b_511b_frames),
3688c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames),
3698c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_1024b_1518b_frames),
3708c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_good_vlan_frames),
3718c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_1519b_2047b_frames),
3728c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames),
3738c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames),
3748c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames),
3758c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_good_frames),
3768c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_total_frames),
3778c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_ucast_frames),
3788c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_mcast_frames),
3798c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_bcast_frames),
3808c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pause_frames),
3818c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_frames),
3828c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_jabber_frames),
3838c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_fcs_err_frames),
3848c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_err),
3858c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_fifo_underruns),
3868c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0),
3878c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1),
3888c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2),
3898c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3),
3908c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4),
3918c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5),
3928c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6),
3938c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7),
3948c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_eee_lpi_events),
3958c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration),
3968c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_total_collisions),
3978c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_bytes),
3988c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_xthol_frames),
3998c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_stat_discard),
4008c2ecf20Sopenharmony_ci	BNXT_TX_STATS_ENTRY(tx_stat_error),
4018c2ecf20Sopenharmony_ci};
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic const struct {
4048c2ecf20Sopenharmony_ci	long offset;
4058c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
4068c2ecf20Sopenharmony_ci} bnxt_port_stats_ext_arr[] = {
4078c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(link_down_events),
4088c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(continuous_pause_events),
4098c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(resume_pause_events),
4108c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(continuous_roce_pause_events),
4118c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(resume_roce_pause_events),
4128c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_COS_ENTRIES,
4138c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_PFC_ENTRIES,
4148c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_bits),
4158c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_buffer_passed_threshold),
4168c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_pcs_symbol_err),
4178c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_ENTRY(rx_corrected_bits),
4188c2ecf20Sopenharmony_ci	BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES,
4198c2ecf20Sopenharmony_ci};
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic const struct {
4228c2ecf20Sopenharmony_ci	long offset;
4238c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
4248c2ecf20Sopenharmony_ci} bnxt_tx_port_stats_ext_arr[] = {
4258c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_COS_ENTRIES,
4268c2ecf20Sopenharmony_ci	BNXT_TX_STATS_EXT_PFC_ENTRIES,
4278c2ecf20Sopenharmony_ci};
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic const struct {
4308c2ecf20Sopenharmony_ci	long base_off;
4318c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
4328c2ecf20Sopenharmony_ci} bnxt_rx_bytes_pri_arr[] = {
4338c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRIES(rx_bytes),
4348c2ecf20Sopenharmony_ci};
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic const struct {
4378c2ecf20Sopenharmony_ci	long base_off;
4388c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
4398c2ecf20Sopenharmony_ci} bnxt_rx_pkts_pri_arr[] = {
4408c2ecf20Sopenharmony_ci	BNXT_RX_STATS_PRI_ENTRIES(rx_packets),
4418c2ecf20Sopenharmony_ci};
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic const struct {
4448c2ecf20Sopenharmony_ci	long base_off;
4458c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
4468c2ecf20Sopenharmony_ci} bnxt_tx_bytes_pri_arr[] = {
4478c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRIES(tx_bytes),
4488c2ecf20Sopenharmony_ci};
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic const struct {
4518c2ecf20Sopenharmony_ci	long base_off;
4528c2ecf20Sopenharmony_ci	char string[ETH_GSTRING_LEN];
4538c2ecf20Sopenharmony_ci} bnxt_tx_pkts_pri_arr[] = {
4548c2ecf20Sopenharmony_ci	BNXT_TX_STATS_PRI_ENTRIES(tx_packets),
4558c2ecf20Sopenharmony_ci};
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci#define BNXT_NUM_SW_FUNC_STATS	ARRAY_SIZE(bnxt_sw_func_stats)
4588c2ecf20Sopenharmony_ci#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
4598c2ecf20Sopenharmony_ci#define BNXT_NUM_STATS_PRI			\
4608c2ecf20Sopenharmony_ci	(ARRAY_SIZE(bnxt_rx_bytes_pri_arr) +	\
4618c2ecf20Sopenharmony_ci	 ARRAY_SIZE(bnxt_rx_pkts_pri_arr) +	\
4628c2ecf20Sopenharmony_ci	 ARRAY_SIZE(bnxt_tx_bytes_pri_arr) +	\
4638c2ecf20Sopenharmony_ci	 ARRAY_SIZE(bnxt_tx_pkts_pri_arr))
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int bnxt_get_num_tpa_ring_stats(struct bnxt *bp)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	if (BNXT_SUPPORTS_TPA(bp)) {
4688c2ecf20Sopenharmony_ci		if (bp->max_tpa_v2) {
4698c2ecf20Sopenharmony_ci			if (BNXT_CHIP_P5_THOR(bp))
4708c2ecf20Sopenharmony_ci				return BNXT_NUM_TPA_RING_STATS_P5;
4718c2ecf20Sopenharmony_ci			return BNXT_NUM_TPA_RING_STATS_P5_SR2;
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci		return BNXT_NUM_TPA_RING_STATS;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci	return 0;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int bnxt_get_num_ring_stats(struct bnxt *bp)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	int rx, tx, cmn;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	rx = NUM_RING_RX_HW_STATS + NUM_RING_RX_SW_STATS +
4838c2ecf20Sopenharmony_ci	     bnxt_get_num_tpa_ring_stats(bp);
4848c2ecf20Sopenharmony_ci	tx = NUM_RING_TX_HW_STATS;
4858c2ecf20Sopenharmony_ci	cmn = NUM_RING_CMN_SW_STATS;
4868c2ecf20Sopenharmony_ci	return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
4878c2ecf20Sopenharmony_ci	       cmn * bp->cp_nr_rings;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic int bnxt_get_num_stats(struct bnxt *bp)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	int num_stats = bnxt_get_num_ring_stats(bp);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	num_stats += BNXT_NUM_SW_FUNC_STATS;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS)
4978c2ecf20Sopenharmony_ci		num_stats += BNXT_NUM_PORT_STATS;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
5008c2ecf20Sopenharmony_ci		num_stats += bp->fw_rx_stats_ext_size +
5018c2ecf20Sopenharmony_ci			     bp->fw_tx_stats_ext_size;
5028c2ecf20Sopenharmony_ci		if (bp->pri2cos_valid)
5038c2ecf20Sopenharmony_ci			num_stats += BNXT_NUM_STATS_PRI;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	return num_stats;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int bnxt_get_sset_count(struct net_device *dev, int sset)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	switch (sset) {
5148c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
5158c2ecf20Sopenharmony_ci		return bnxt_get_num_stats(bp);
5168c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
5178c2ecf20Sopenharmony_ci		if (!bp->num_tests)
5188c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
5198c2ecf20Sopenharmony_ci		return bp->num_tests;
5208c2ecf20Sopenharmony_ci	default:
5218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic bool is_rx_ring(struct bnxt *bp, int ring_num)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	return ring_num < bp->rx_nr_rings;
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic bool is_tx_ring(struct bnxt *bp, int ring_num)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	int tx_base = 0;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (!(bp->flags & BNXT_FLAG_SHARED_RINGS))
5358c2ecf20Sopenharmony_ci		tx_base = bp->rx_nr_rings;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (ring_num >= tx_base && ring_num < (tx_base + bp->tx_nr_rings))
5388c2ecf20Sopenharmony_ci		return true;
5398c2ecf20Sopenharmony_ci	return false;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic void bnxt_get_ethtool_stats(struct net_device *dev,
5438c2ecf20Sopenharmony_ci				   struct ethtool_stats *stats, u64 *buf)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	u32 i, j = 0;
5468c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
5478c2ecf20Sopenharmony_ci	u32 tpa_stats;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (!bp->bnapi) {
5508c2ecf20Sopenharmony_ci		j += bnxt_get_num_ring_stats(bp) + BNXT_NUM_SW_FUNC_STATS;
5518c2ecf20Sopenharmony_ci		goto skip_ring_stats;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++)
5558c2ecf20Sopenharmony_ci		bnxt_sw_func_stats[i].counter = 0;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	tpa_stats = bnxt_get_num_tpa_ring_stats(bp);
5588c2ecf20Sopenharmony_ci	for (i = 0; i < bp->cp_nr_rings; i++) {
5598c2ecf20Sopenharmony_ci		struct bnxt_napi *bnapi = bp->bnapi[i];
5608c2ecf20Sopenharmony_ci		struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
5618c2ecf20Sopenharmony_ci		u64 *sw_stats = cpr->stats.sw_stats;
5628c2ecf20Sopenharmony_ci		u64 *sw;
5638c2ecf20Sopenharmony_ci		int k;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci		if (is_rx_ring(bp, i)) {
5668c2ecf20Sopenharmony_ci			for (k = 0; k < NUM_RING_RX_HW_STATS; j++, k++)
5678c2ecf20Sopenharmony_ci				buf[j] = sw_stats[k];
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci		if (is_tx_ring(bp, i)) {
5708c2ecf20Sopenharmony_ci			k = NUM_RING_RX_HW_STATS;
5718c2ecf20Sopenharmony_ci			for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS;
5728c2ecf20Sopenharmony_ci			       j++, k++)
5738c2ecf20Sopenharmony_ci				buf[j] = sw_stats[k];
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci		if (!tpa_stats || !is_rx_ring(bp, i))
5768c2ecf20Sopenharmony_ci			goto skip_tpa_ring_stats;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci		k = NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS;
5798c2ecf20Sopenharmony_ci		for (; k < NUM_RING_RX_HW_STATS + NUM_RING_TX_HW_STATS +
5808c2ecf20Sopenharmony_ci			   tpa_stats; j++, k++)
5818c2ecf20Sopenharmony_ci			buf[j] = sw_stats[k];
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ciskip_tpa_ring_stats:
5848c2ecf20Sopenharmony_ci		sw = (u64 *)&cpr->sw_stats.rx;
5858c2ecf20Sopenharmony_ci		if (is_rx_ring(bp, i)) {
5868c2ecf20Sopenharmony_ci			for (k = 0; k < NUM_RING_RX_SW_STATS; j++, k++)
5878c2ecf20Sopenharmony_ci				buf[j] = sw[k];
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		sw = (u64 *)&cpr->sw_stats.cmn;
5918c2ecf20Sopenharmony_ci		for (k = 0; k < NUM_RING_CMN_SW_STATS; j++, k++)
5928c2ecf20Sopenharmony_ci			buf[j] = sw[k];
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci		bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter +=
5958c2ecf20Sopenharmony_ci			BNXT_GET_RING_STATS64(sw_stats, rx_discard_pkts);
5968c2ecf20Sopenharmony_ci		bnxt_sw_func_stats[TX_TOTAL_DISCARDS].counter +=
5978c2ecf20Sopenharmony_ci			BNXT_GET_RING_STATS64(sw_stats, tx_discard_pkts);
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++, j++)
6018c2ecf20Sopenharmony_ci		buf[j] = bnxt_sw_func_stats[i].counter;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ciskip_ring_stats:
6048c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS) {
6058c2ecf20Sopenharmony_ci		u64 *port_stats = bp->port_stats.sw_stats;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci		for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++)
6088c2ecf20Sopenharmony_ci			buf[j] = *(port_stats + bnxt_port_stats_arr[i].offset);
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
6118c2ecf20Sopenharmony_ci		u64 *rx_port_stats_ext = bp->rx_port_stats_ext.sw_stats;
6128c2ecf20Sopenharmony_ci		u64 *tx_port_stats_ext = bp->tx_port_stats_ext.sw_stats;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		for (i = 0; i < bp->fw_rx_stats_ext_size; i++, j++) {
6158c2ecf20Sopenharmony_ci			buf[j] = *(rx_port_stats_ext +
6168c2ecf20Sopenharmony_ci				   bnxt_port_stats_ext_arr[i].offset);
6178c2ecf20Sopenharmony_ci		}
6188c2ecf20Sopenharmony_ci		for (i = 0; i < bp->fw_tx_stats_ext_size; i++, j++) {
6198c2ecf20Sopenharmony_ci			buf[j] = *(tx_port_stats_ext +
6208c2ecf20Sopenharmony_ci				   bnxt_tx_port_stats_ext_arr[i].offset);
6218c2ecf20Sopenharmony_ci		}
6228c2ecf20Sopenharmony_ci		if (bp->pri2cos_valid) {
6238c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
6248c2ecf20Sopenharmony_ci				long n = bnxt_rx_bytes_pri_arr[i].base_off +
6258c2ecf20Sopenharmony_ci					 bp->pri2cos_idx[i];
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci				buf[j] = *(rx_port_stats_ext + n);
6288c2ecf20Sopenharmony_ci			}
6298c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
6308c2ecf20Sopenharmony_ci				long n = bnxt_rx_pkts_pri_arr[i].base_off +
6318c2ecf20Sopenharmony_ci					 bp->pri2cos_idx[i];
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci				buf[j] = *(rx_port_stats_ext + n);
6348c2ecf20Sopenharmony_ci			}
6358c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
6368c2ecf20Sopenharmony_ci				long n = bnxt_tx_bytes_pri_arr[i].base_off +
6378c2ecf20Sopenharmony_ci					 bp->pri2cos_idx[i];
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci				buf[j] = *(tx_port_stats_ext + n);
6408c2ecf20Sopenharmony_ci			}
6418c2ecf20Sopenharmony_ci			for (i = 0; i < 8; i++, j++) {
6428c2ecf20Sopenharmony_ci				long n = bnxt_tx_pkts_pri_arr[i].base_off +
6438c2ecf20Sopenharmony_ci					 bp->pri2cos_idx[i];
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci				buf[j] = *(tx_port_stats_ext + n);
6468c2ecf20Sopenharmony_ci			}
6478c2ecf20Sopenharmony_ci		}
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
6548c2ecf20Sopenharmony_ci	static const char * const *str;
6558c2ecf20Sopenharmony_ci	u32 i, j, num_str;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	switch (stringset) {
6588c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
6598c2ecf20Sopenharmony_ci		for (i = 0; i < bp->cp_nr_rings; i++) {
6608c2ecf20Sopenharmony_ci			if (is_rx_ring(bp, i)) {
6618c2ecf20Sopenharmony_ci				num_str = NUM_RING_RX_HW_STATS;
6628c2ecf20Sopenharmony_ci				for (j = 0; j < num_str; j++) {
6638c2ecf20Sopenharmony_ci					sprintf(buf, "[%d]: %s", i,
6648c2ecf20Sopenharmony_ci						bnxt_ring_rx_stats_str[j]);
6658c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
6668c2ecf20Sopenharmony_ci				}
6678c2ecf20Sopenharmony_ci			}
6688c2ecf20Sopenharmony_ci			if (is_tx_ring(bp, i)) {
6698c2ecf20Sopenharmony_ci				num_str = NUM_RING_TX_HW_STATS;
6708c2ecf20Sopenharmony_ci				for (j = 0; j < num_str; j++) {
6718c2ecf20Sopenharmony_ci					sprintf(buf, "[%d]: %s", i,
6728c2ecf20Sopenharmony_ci						bnxt_ring_tx_stats_str[j]);
6738c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
6748c2ecf20Sopenharmony_ci				}
6758c2ecf20Sopenharmony_ci			}
6768c2ecf20Sopenharmony_ci			num_str = bnxt_get_num_tpa_ring_stats(bp);
6778c2ecf20Sopenharmony_ci			if (!num_str || !is_rx_ring(bp, i))
6788c2ecf20Sopenharmony_ci				goto skip_tpa_stats;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci			if (bp->max_tpa_v2)
6818c2ecf20Sopenharmony_ci				str = bnxt_ring_tpa2_stats_str;
6828c2ecf20Sopenharmony_ci			else
6838c2ecf20Sopenharmony_ci				str = bnxt_ring_tpa_stats_str;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci			for (j = 0; j < num_str; j++) {
6868c2ecf20Sopenharmony_ci				sprintf(buf, "[%d]: %s", i, str[j]);
6878c2ecf20Sopenharmony_ci				buf += ETH_GSTRING_LEN;
6888c2ecf20Sopenharmony_ci			}
6898c2ecf20Sopenharmony_ciskip_tpa_stats:
6908c2ecf20Sopenharmony_ci			if (is_rx_ring(bp, i)) {
6918c2ecf20Sopenharmony_ci				num_str = NUM_RING_RX_SW_STATS;
6928c2ecf20Sopenharmony_ci				for (j = 0; j < num_str; j++) {
6938c2ecf20Sopenharmony_ci					sprintf(buf, "[%d]: %s", i,
6948c2ecf20Sopenharmony_ci						bnxt_rx_sw_stats_str[j]);
6958c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
6968c2ecf20Sopenharmony_ci				}
6978c2ecf20Sopenharmony_ci			}
6988c2ecf20Sopenharmony_ci			num_str = NUM_RING_CMN_SW_STATS;
6998c2ecf20Sopenharmony_ci			for (j = 0; j < num_str; j++) {
7008c2ecf20Sopenharmony_ci				sprintf(buf, "[%d]: %s", i,
7018c2ecf20Sopenharmony_ci					bnxt_cmn_sw_stats_str[j]);
7028c2ecf20Sopenharmony_ci				buf += ETH_GSTRING_LEN;
7038c2ecf20Sopenharmony_ci			}
7048c2ecf20Sopenharmony_ci		}
7058c2ecf20Sopenharmony_ci		for (i = 0; i < BNXT_NUM_SW_FUNC_STATS; i++) {
7068c2ecf20Sopenharmony_ci			strcpy(buf, bnxt_sw_func_stats[i].string);
7078c2ecf20Sopenharmony_ci			buf += ETH_GSTRING_LEN;
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		if (bp->flags & BNXT_FLAG_PORT_STATS) {
7118c2ecf20Sopenharmony_ci			for (i = 0; i < BNXT_NUM_PORT_STATS; i++) {
7128c2ecf20Sopenharmony_ci				strcpy(buf, bnxt_port_stats_arr[i].string);
7138c2ecf20Sopenharmony_ci				buf += ETH_GSTRING_LEN;
7148c2ecf20Sopenharmony_ci			}
7158c2ecf20Sopenharmony_ci		}
7168c2ecf20Sopenharmony_ci		if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) {
7178c2ecf20Sopenharmony_ci			for (i = 0; i < bp->fw_rx_stats_ext_size; i++) {
7188c2ecf20Sopenharmony_ci				strcpy(buf, bnxt_port_stats_ext_arr[i].string);
7198c2ecf20Sopenharmony_ci				buf += ETH_GSTRING_LEN;
7208c2ecf20Sopenharmony_ci			}
7218c2ecf20Sopenharmony_ci			for (i = 0; i < bp->fw_tx_stats_ext_size; i++) {
7228c2ecf20Sopenharmony_ci				strcpy(buf,
7238c2ecf20Sopenharmony_ci				       bnxt_tx_port_stats_ext_arr[i].string);
7248c2ecf20Sopenharmony_ci				buf += ETH_GSTRING_LEN;
7258c2ecf20Sopenharmony_ci			}
7268c2ecf20Sopenharmony_ci			if (bp->pri2cos_valid) {
7278c2ecf20Sopenharmony_ci				for (i = 0; i < 8; i++) {
7288c2ecf20Sopenharmony_ci					strcpy(buf,
7298c2ecf20Sopenharmony_ci					       bnxt_rx_bytes_pri_arr[i].string);
7308c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
7318c2ecf20Sopenharmony_ci				}
7328c2ecf20Sopenharmony_ci				for (i = 0; i < 8; i++) {
7338c2ecf20Sopenharmony_ci					strcpy(buf,
7348c2ecf20Sopenharmony_ci					       bnxt_rx_pkts_pri_arr[i].string);
7358c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
7368c2ecf20Sopenharmony_ci				}
7378c2ecf20Sopenharmony_ci				for (i = 0; i < 8; i++) {
7388c2ecf20Sopenharmony_ci					strcpy(buf,
7398c2ecf20Sopenharmony_ci					       bnxt_tx_bytes_pri_arr[i].string);
7408c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
7418c2ecf20Sopenharmony_ci				}
7428c2ecf20Sopenharmony_ci				for (i = 0; i < 8; i++) {
7438c2ecf20Sopenharmony_ci					strcpy(buf,
7448c2ecf20Sopenharmony_ci					       bnxt_tx_pkts_pri_arr[i].string);
7458c2ecf20Sopenharmony_ci					buf += ETH_GSTRING_LEN;
7468c2ecf20Sopenharmony_ci				}
7478c2ecf20Sopenharmony_ci			}
7488c2ecf20Sopenharmony_ci		}
7498c2ecf20Sopenharmony_ci		break;
7508c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
7518c2ecf20Sopenharmony_ci		if (bp->num_tests)
7528c2ecf20Sopenharmony_ci			memcpy(buf, bp->test_info->string,
7538c2ecf20Sopenharmony_ci			       bp->num_tests * ETH_GSTRING_LEN);
7548c2ecf20Sopenharmony_ci		break;
7558c2ecf20Sopenharmony_ci	default:
7568c2ecf20Sopenharmony_ci		netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n",
7578c2ecf20Sopenharmony_ci			   stringset);
7588c2ecf20Sopenharmony_ci		break;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_cistatic void bnxt_get_ringparam(struct net_device *dev,
7638c2ecf20Sopenharmony_ci			       struct ethtool_ringparam *ering)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT;
7688c2ecf20Sopenharmony_ci	ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT;
7698c2ecf20Sopenharmony_ci	ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	ering->rx_pending = bp->rx_ring_size;
7728c2ecf20Sopenharmony_ci	ering->rx_jumbo_pending = bp->rx_agg_ring_size;
7738c2ecf20Sopenharmony_ci	ering->tx_pending = bp->tx_ring_size;
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_cistatic int bnxt_set_ringparam(struct net_device *dev,
7778c2ecf20Sopenharmony_ci			      struct ethtool_ringparam *ering)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) ||
7828c2ecf20Sopenharmony_ci	    (ering->tx_pending > BNXT_MAX_TX_DESC_CNT) ||
7838c2ecf20Sopenharmony_ci	    (ering->tx_pending < BNXT_MIN_TX_DESC_CNT))
7848c2ecf20Sopenharmony_ci		return -EINVAL;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (netif_running(dev))
7878c2ecf20Sopenharmony_ci		bnxt_close_nic(bp, false, false);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	bp->rx_ring_size = ering->rx_pending;
7908c2ecf20Sopenharmony_ci	bp->tx_ring_size = ering->tx_pending;
7918c2ecf20Sopenharmony_ci	bnxt_set_ring_params(bp);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (netif_running(dev))
7948c2ecf20Sopenharmony_ci		return bnxt_open_nic(bp, false, false);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	return 0;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic void bnxt_get_channels(struct net_device *dev,
8008c2ecf20Sopenharmony_ci			      struct ethtool_channels *channel)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
8038c2ecf20Sopenharmony_ci	struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
8048c2ecf20Sopenharmony_ci	int max_rx_rings, max_tx_rings, tcs;
8058c2ecf20Sopenharmony_ci	int max_tx_sch_inputs, tx_grps;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* Get the most up-to-date max_tx_sch_inputs. */
8088c2ecf20Sopenharmony_ci	if (netif_running(dev) && BNXT_NEW_RM(bp))
8098c2ecf20Sopenharmony_ci		bnxt_hwrm_func_resc_qcaps(bp, false);
8108c2ecf20Sopenharmony_ci	max_tx_sch_inputs = hw_resc->max_tx_sch_inputs;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true);
8138c2ecf20Sopenharmony_ci	if (max_tx_sch_inputs)
8148c2ecf20Sopenharmony_ci		max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	tcs = netdev_get_num_tc(dev);
8178c2ecf20Sopenharmony_ci	tx_grps = max(tcs, 1);
8188c2ecf20Sopenharmony_ci	if (bp->tx_nr_rings_xdp)
8198c2ecf20Sopenharmony_ci		tx_grps++;
8208c2ecf20Sopenharmony_ci	max_tx_rings /= tx_grps;
8218c2ecf20Sopenharmony_ci	channel->max_combined = min_t(int, max_rx_rings, max_tx_rings);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) {
8248c2ecf20Sopenharmony_ci		max_rx_rings = 0;
8258c2ecf20Sopenharmony_ci		max_tx_rings = 0;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci	if (max_tx_sch_inputs)
8288c2ecf20Sopenharmony_ci		max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (tcs > 1)
8318c2ecf20Sopenharmony_ci		max_tx_rings /= tcs;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	channel->max_rx = max_rx_rings;
8348c2ecf20Sopenharmony_ci	channel->max_tx = max_tx_rings;
8358c2ecf20Sopenharmony_ci	channel->max_other = 0;
8368c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_SHARED_RINGS) {
8378c2ecf20Sopenharmony_ci		channel->combined_count = bp->rx_nr_rings;
8388c2ecf20Sopenharmony_ci		if (BNXT_CHIP_TYPE_NITRO_A0(bp))
8398c2ecf20Sopenharmony_ci			channel->combined_count--;
8408c2ecf20Sopenharmony_ci	} else {
8418c2ecf20Sopenharmony_ci		if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) {
8428c2ecf20Sopenharmony_ci			channel->rx_count = bp->rx_nr_rings;
8438c2ecf20Sopenharmony_ci			channel->tx_count = bp->tx_nr_rings_per_tc;
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cistatic int bnxt_set_channels(struct net_device *dev,
8498c2ecf20Sopenharmony_ci			     struct ethtool_channels *channel)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
8528c2ecf20Sopenharmony_ci	int req_tx_rings, req_rx_rings, tcs;
8538c2ecf20Sopenharmony_ci	bool sh = false;
8548c2ecf20Sopenharmony_ci	int tx_xdp = 0;
8558c2ecf20Sopenharmony_ci	int rc = 0;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	if (channel->other_count)
8588c2ecf20Sopenharmony_ci		return -EINVAL;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	if (!channel->combined_count &&
8618c2ecf20Sopenharmony_ci	    (!channel->rx_count || !channel->tx_count))
8628c2ecf20Sopenharmony_ci		return -EINVAL;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if (channel->combined_count &&
8658c2ecf20Sopenharmony_ci	    (channel->rx_count || channel->tx_count))
8668c2ecf20Sopenharmony_ci		return -EINVAL;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count ||
8698c2ecf20Sopenharmony_ci					    channel->tx_count))
8708c2ecf20Sopenharmony_ci		return -EINVAL;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (channel->combined_count)
8738c2ecf20Sopenharmony_ci		sh = true;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	tcs = netdev_get_num_tc(dev);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	req_tx_rings = sh ? channel->combined_count : channel->tx_count;
8788c2ecf20Sopenharmony_ci	req_rx_rings = sh ? channel->combined_count : channel->rx_count;
8798c2ecf20Sopenharmony_ci	if (bp->tx_nr_rings_xdp) {
8808c2ecf20Sopenharmony_ci		if (!sh) {
8818c2ecf20Sopenharmony_ci			netdev_err(dev, "Only combined mode supported when XDP is enabled.\n");
8828c2ecf20Sopenharmony_ci			return -EINVAL;
8838c2ecf20Sopenharmony_ci		}
8848c2ecf20Sopenharmony_ci		tx_xdp = req_rx_rings;
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci	rc = bnxt_check_rings(bp, req_tx_rings, req_rx_rings, sh, tcs, tx_xdp);
8878c2ecf20Sopenharmony_ci	if (rc) {
8888c2ecf20Sopenharmony_ci		netdev_warn(dev, "Unable to allocate the requested rings\n");
8898c2ecf20Sopenharmony_ci		return rc;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (bnxt_get_nr_rss_ctxs(bp, req_rx_rings) !=
8938c2ecf20Sopenharmony_ci	    bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) &&
8948c2ecf20Sopenharmony_ci	    (dev->priv_flags & IFF_RXFH_CONFIGURED)) {
8958c2ecf20Sopenharmony_ci		netdev_warn(dev, "RSS table size change required, RSS table entries must be default to proceed\n");
8968c2ecf20Sopenharmony_ci		return -EINVAL;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	if (netif_running(dev)) {
9008c2ecf20Sopenharmony_ci		if (BNXT_PF(bp)) {
9018c2ecf20Sopenharmony_ci			/* TODO CHIMP_FW: Send message to all VF's
9028c2ecf20Sopenharmony_ci			 * before PF unload
9038c2ecf20Sopenharmony_ci			 */
9048c2ecf20Sopenharmony_ci		}
9058c2ecf20Sopenharmony_ci		rc = bnxt_close_nic(bp, true, false);
9068c2ecf20Sopenharmony_ci		if (rc) {
9078c2ecf20Sopenharmony_ci			netdev_err(bp->dev, "Set channel failure rc :%x\n",
9088c2ecf20Sopenharmony_ci				   rc);
9098c2ecf20Sopenharmony_ci			return rc;
9108c2ecf20Sopenharmony_ci		}
9118c2ecf20Sopenharmony_ci	}
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	if (sh) {
9148c2ecf20Sopenharmony_ci		bp->flags |= BNXT_FLAG_SHARED_RINGS;
9158c2ecf20Sopenharmony_ci		bp->rx_nr_rings = channel->combined_count;
9168c2ecf20Sopenharmony_ci		bp->tx_nr_rings_per_tc = channel->combined_count;
9178c2ecf20Sopenharmony_ci	} else {
9188c2ecf20Sopenharmony_ci		bp->flags &= ~BNXT_FLAG_SHARED_RINGS;
9198c2ecf20Sopenharmony_ci		bp->rx_nr_rings = channel->rx_count;
9208c2ecf20Sopenharmony_ci		bp->tx_nr_rings_per_tc = channel->tx_count;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci	bp->tx_nr_rings_xdp = tx_xdp;
9238c2ecf20Sopenharmony_ci	bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp;
9248c2ecf20Sopenharmony_ci	if (tcs > 1)
9258c2ecf20Sopenharmony_ci		bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
9288c2ecf20Sopenharmony_ci			       bp->tx_nr_rings + bp->rx_nr_rings;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	/* After changing number of rx channels, update NTUPLE feature. */
9318c2ecf20Sopenharmony_ci	netdev_update_features(dev);
9328c2ecf20Sopenharmony_ci	if (netif_running(dev)) {
9338c2ecf20Sopenharmony_ci		rc = bnxt_open_nic(bp, true, false);
9348c2ecf20Sopenharmony_ci		if ((!rc) && BNXT_PF(bp)) {
9358c2ecf20Sopenharmony_ci			/* TODO CHIMP_FW: Send message to all VF's
9368c2ecf20Sopenharmony_ci			 * to renable
9378c2ecf20Sopenharmony_ci			 */
9388c2ecf20Sopenharmony_ci		}
9398c2ecf20Sopenharmony_ci	} else {
9408c2ecf20Sopenharmony_ci		rc = bnxt_reserve_rings(bp, true);
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return rc;
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
9478c2ecf20Sopenharmony_cistatic int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
9488c2ecf20Sopenharmony_ci			    u32 *rule_locs)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	int i, j = 0;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	cmd->data = bp->ntp_fltr_count;
9538c2ecf20Sopenharmony_ci	for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
9548c2ecf20Sopenharmony_ci		struct hlist_head *head;
9558c2ecf20Sopenharmony_ci		struct bnxt_ntuple_filter *fltr;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci		head = &bp->ntp_fltr_hash_tbl[i];
9588c2ecf20Sopenharmony_ci		rcu_read_lock();
9598c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(fltr, head, hash) {
9608c2ecf20Sopenharmony_ci			if (j == cmd->rule_cnt)
9618c2ecf20Sopenharmony_ci				break;
9628c2ecf20Sopenharmony_ci			rule_locs[j++] = fltr->sw_id;
9638c2ecf20Sopenharmony_ci		}
9648c2ecf20Sopenharmony_ci		rcu_read_unlock();
9658c2ecf20Sopenharmony_ci		if (j == cmd->rule_cnt)
9668c2ecf20Sopenharmony_ci			break;
9678c2ecf20Sopenharmony_ci	}
9688c2ecf20Sopenharmony_ci	cmd->rule_cnt = j;
9698c2ecf20Sopenharmony_ci	return 0;
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_cistatic int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	struct ethtool_rx_flow_spec *fs =
9758c2ecf20Sopenharmony_ci		(struct ethtool_rx_flow_spec *)&cmd->fs;
9768c2ecf20Sopenharmony_ci	struct bnxt_ntuple_filter *fltr;
9778c2ecf20Sopenharmony_ci	struct flow_keys *fkeys;
9788c2ecf20Sopenharmony_ci	int i, rc = -EINVAL;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
9818c2ecf20Sopenharmony_ci		return rc;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
9848c2ecf20Sopenharmony_ci		struct hlist_head *head;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		head = &bp->ntp_fltr_hash_tbl[i];
9878c2ecf20Sopenharmony_ci		rcu_read_lock();
9888c2ecf20Sopenharmony_ci		hlist_for_each_entry_rcu(fltr, head, hash) {
9898c2ecf20Sopenharmony_ci			if (fltr->sw_id == fs->location)
9908c2ecf20Sopenharmony_ci				goto fltr_found;
9918c2ecf20Sopenharmony_ci		}
9928c2ecf20Sopenharmony_ci		rcu_read_unlock();
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci	return rc;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_cifltr_found:
9978c2ecf20Sopenharmony_ci	fkeys = &fltr->fkeys;
9988c2ecf20Sopenharmony_ci	if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
9998c2ecf20Sopenharmony_ci		if (fkeys->basic.ip_proto == IPPROTO_TCP)
10008c2ecf20Sopenharmony_ci			fs->flow_type = TCP_V4_FLOW;
10018c2ecf20Sopenharmony_ci		else if (fkeys->basic.ip_proto == IPPROTO_UDP)
10028c2ecf20Sopenharmony_ci			fs->flow_type = UDP_V4_FLOW;
10038c2ecf20Sopenharmony_ci		else
10048c2ecf20Sopenharmony_ci			goto fltr_err;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci		fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
10078c2ecf20Sopenharmony_ci		fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
10108c2ecf20Sopenharmony_ci		fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci		fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
10138c2ecf20Sopenharmony_ci		fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci		fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
10168c2ecf20Sopenharmony_ci		fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
10178c2ecf20Sopenharmony_ci	} else {
10188c2ecf20Sopenharmony_ci		int i;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci		if (fkeys->basic.ip_proto == IPPROTO_TCP)
10218c2ecf20Sopenharmony_ci			fs->flow_type = TCP_V6_FLOW;
10228c2ecf20Sopenharmony_ci		else if (fkeys->basic.ip_proto == IPPROTO_UDP)
10238c2ecf20Sopenharmony_ci			fs->flow_type = UDP_V6_FLOW;
10248c2ecf20Sopenharmony_ci		else
10258c2ecf20Sopenharmony_ci			goto fltr_err;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci		*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
10288c2ecf20Sopenharmony_ci			fkeys->addrs.v6addrs.src;
10298c2ecf20Sopenharmony_ci		*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
10308c2ecf20Sopenharmony_ci			fkeys->addrs.v6addrs.dst;
10318c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++) {
10328c2ecf20Sopenharmony_ci			fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0);
10338c2ecf20Sopenharmony_ci			fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0);
10348c2ecf20Sopenharmony_ci		}
10358c2ecf20Sopenharmony_ci		fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
10368c2ecf20Sopenharmony_ci		fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
10398c2ecf20Sopenharmony_ci		fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0);
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	fs->ring_cookie = fltr->rxq;
10438c2ecf20Sopenharmony_ci	rc = 0;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cifltr_err:
10468c2ecf20Sopenharmony_ci	rcu_read_unlock();
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	return rc;
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci#endif
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_cistatic u64 get_ethtool_ipv4_rss(struct bnxt *bp)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
10558c2ecf20Sopenharmony_ci		return RXH_IP_SRC | RXH_IP_DST;
10568c2ecf20Sopenharmony_ci	return 0;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic u64 get_ethtool_ipv6_rss(struct bnxt *bp)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
10628c2ecf20Sopenharmony_ci		return RXH_IP_SRC | RXH_IP_DST;
10638c2ecf20Sopenharmony_ci	return 0;
10648c2ecf20Sopenharmony_ci}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_cistatic int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	cmd->data = 0;
10698c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
10708c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
10718c2ecf20Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4)
10728c2ecf20Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
10738c2ecf20Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
10748c2ecf20Sopenharmony_ci		cmd->data |= get_ethtool_ipv4_rss(bp);
10758c2ecf20Sopenharmony_ci		break;
10768c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
10778c2ecf20Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
10788c2ecf20Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
10798c2ecf20Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
10808c2ecf20Sopenharmony_ci		fallthrough;
10818c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
10828c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
10838c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
10848c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
10858c2ecf20Sopenharmony_ci	case IPV4_FLOW:
10868c2ecf20Sopenharmony_ci		cmd->data |= get_ethtool_ipv4_rss(bp);
10878c2ecf20Sopenharmony_ci		break;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
10908c2ecf20Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6)
10918c2ecf20Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
10928c2ecf20Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
10938c2ecf20Sopenharmony_ci		cmd->data |= get_ethtool_ipv6_rss(bp);
10948c2ecf20Sopenharmony_ci		break;
10958c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
10968c2ecf20Sopenharmony_ci		if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
10978c2ecf20Sopenharmony_ci			cmd->data |= RXH_IP_SRC | RXH_IP_DST |
10988c2ecf20Sopenharmony_ci				     RXH_L4_B_0_1 | RXH_L4_B_2_3;
10998c2ecf20Sopenharmony_ci		fallthrough;
11008c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
11018c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
11028c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
11038c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
11048c2ecf20Sopenharmony_ci	case IPV6_FLOW:
11058c2ecf20Sopenharmony_ci		cmd->data |= get_ethtool_ipv6_rss(bp);
11068c2ecf20Sopenharmony_ci		break;
11078c2ecf20Sopenharmony_ci	}
11088c2ecf20Sopenharmony_ci	return 0;
11098c2ecf20Sopenharmony_ci}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
11128c2ecf20Sopenharmony_ci#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST)
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_cistatic int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	u32 rss_hash_cfg = bp->rss_hash_cfg;
11178c2ecf20Sopenharmony_ci	int tuple, rc = 0;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (cmd->data == RXH_4TUPLE)
11208c2ecf20Sopenharmony_ci		tuple = 4;
11218c2ecf20Sopenharmony_ci	else if (cmd->data == RXH_2TUPLE)
11228c2ecf20Sopenharmony_ci		tuple = 2;
11238c2ecf20Sopenharmony_ci	else if (!cmd->data)
11248c2ecf20Sopenharmony_ci		tuple = 0;
11258c2ecf20Sopenharmony_ci	else
11268c2ecf20Sopenharmony_ci		return -EINVAL;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	if (cmd->flow_type == TCP_V4_FLOW) {
11298c2ecf20Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
11308c2ecf20Sopenharmony_ci		if (tuple == 4)
11318c2ecf20Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
11328c2ecf20Sopenharmony_ci	} else if (cmd->flow_type == UDP_V4_FLOW) {
11338c2ecf20Sopenharmony_ci		if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
11348c2ecf20Sopenharmony_ci			return -EINVAL;
11358c2ecf20Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
11368c2ecf20Sopenharmony_ci		if (tuple == 4)
11378c2ecf20Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
11388c2ecf20Sopenharmony_ci	} else if (cmd->flow_type == TCP_V6_FLOW) {
11398c2ecf20Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
11408c2ecf20Sopenharmony_ci		if (tuple == 4)
11418c2ecf20Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
11428c2ecf20Sopenharmony_ci	} else if (cmd->flow_type == UDP_V6_FLOW) {
11438c2ecf20Sopenharmony_ci		if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
11448c2ecf20Sopenharmony_ci			return -EINVAL;
11458c2ecf20Sopenharmony_ci		rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
11468c2ecf20Sopenharmony_ci		if (tuple == 4)
11478c2ecf20Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
11488c2ecf20Sopenharmony_ci	} else if (tuple == 4) {
11498c2ecf20Sopenharmony_ci		return -EINVAL;
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
11538c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
11548c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
11558c2ecf20Sopenharmony_ci	case SCTP_V4_FLOW:
11568c2ecf20Sopenharmony_ci	case AH_ESP_V4_FLOW:
11578c2ecf20Sopenharmony_ci	case AH_V4_FLOW:
11588c2ecf20Sopenharmony_ci	case ESP_V4_FLOW:
11598c2ecf20Sopenharmony_ci	case IPV4_FLOW:
11608c2ecf20Sopenharmony_ci		if (tuple == 2)
11618c2ecf20Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
11628c2ecf20Sopenharmony_ci		else if (!tuple)
11638c2ecf20Sopenharmony_ci			rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
11648c2ecf20Sopenharmony_ci		break;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
11678c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
11688c2ecf20Sopenharmony_ci	case SCTP_V6_FLOW:
11698c2ecf20Sopenharmony_ci	case AH_ESP_V6_FLOW:
11708c2ecf20Sopenharmony_ci	case AH_V6_FLOW:
11718c2ecf20Sopenharmony_ci	case ESP_V6_FLOW:
11728c2ecf20Sopenharmony_ci	case IPV6_FLOW:
11738c2ecf20Sopenharmony_ci		if (tuple == 2)
11748c2ecf20Sopenharmony_ci			rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
11758c2ecf20Sopenharmony_ci		else if (!tuple)
11768c2ecf20Sopenharmony_ci			rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
11778c2ecf20Sopenharmony_ci		break;
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (bp->rss_hash_cfg == rss_hash_cfg)
11818c2ecf20Sopenharmony_ci		return 0;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	bp->rss_hash_cfg = rss_hash_cfg;
11848c2ecf20Sopenharmony_ci	if (netif_running(bp->dev)) {
11858c2ecf20Sopenharmony_ci		bnxt_close_nic(bp, false, false);
11868c2ecf20Sopenharmony_ci		rc = bnxt_open_nic(bp, false, false);
11878c2ecf20Sopenharmony_ci	}
11888c2ecf20Sopenharmony_ci	return rc;
11898c2ecf20Sopenharmony_ci}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_cistatic int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
11928c2ecf20Sopenharmony_ci			  u32 *rule_locs)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
11958c2ecf20Sopenharmony_ci	int rc = 0;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
11988c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
11998c2ecf20Sopenharmony_ci	case ETHTOOL_GRXRINGS:
12008c2ecf20Sopenharmony_ci		cmd->data = bp->rx_nr_rings;
12018c2ecf20Sopenharmony_ci		break;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
12048c2ecf20Sopenharmony_ci		cmd->rule_cnt = bp->ntp_fltr_count;
12058c2ecf20Sopenharmony_ci		cmd->data = BNXT_NTP_FLTR_MAX_FLTR;
12068c2ecf20Sopenharmony_ci		break;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
12098c2ecf20Sopenharmony_ci		rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs);
12108c2ecf20Sopenharmony_ci		break;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
12138c2ecf20Sopenharmony_ci		rc = bnxt_grxclsrule(bp, cmd);
12148c2ecf20Sopenharmony_ci		break;
12158c2ecf20Sopenharmony_ci#endif
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	case ETHTOOL_GRXFH:
12188c2ecf20Sopenharmony_ci		rc = bnxt_grxfh(bp, cmd);
12198c2ecf20Sopenharmony_ci		break;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	default:
12228c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
12238c2ecf20Sopenharmony_ci		break;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	return rc;
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cistatic int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
12328c2ecf20Sopenharmony_ci	int rc;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
12358c2ecf20Sopenharmony_ci	case ETHTOOL_SRXFH:
12368c2ecf20Sopenharmony_ci		rc = bnxt_srxfh(bp, cmd);
12378c2ecf20Sopenharmony_ci		break;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	default:
12408c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
12418c2ecf20Sopenharmony_ci		break;
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci	return rc;
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ciu32 bnxt_get_rxfh_indir_size(struct net_device *dev)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_CHIP_P5)
12518c2ecf20Sopenharmony_ci		return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5);
12528c2ecf20Sopenharmony_ci	return HW_HASH_INDEX_SIZE;
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_cistatic u32 bnxt_get_rxfh_key_size(struct net_device *dev)
12568c2ecf20Sopenharmony_ci{
12578c2ecf20Sopenharmony_ci	return HW_HASH_KEY_SIZE;
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
12618c2ecf20Sopenharmony_ci			 u8 *hfunc)
12628c2ecf20Sopenharmony_ci{
12638c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
12648c2ecf20Sopenharmony_ci	struct bnxt_vnic_info *vnic;
12658c2ecf20Sopenharmony_ci	u32 i, tbl_size;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	if (hfunc)
12688c2ecf20Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	if (!bp->vnic_info)
12718c2ecf20Sopenharmony_ci		return 0;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	vnic = &bp->vnic_info[0];
12748c2ecf20Sopenharmony_ci	if (indir && bp->rss_indir_tbl) {
12758c2ecf20Sopenharmony_ci		tbl_size = bnxt_get_rxfh_indir_size(dev);
12768c2ecf20Sopenharmony_ci		for (i = 0; i < tbl_size; i++)
12778c2ecf20Sopenharmony_ci			indir[i] = bp->rss_indir_tbl[i];
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	if (key && vnic->rss_hash_key)
12818c2ecf20Sopenharmony_ci		memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	return 0;
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_cistatic int bnxt_set_rxfh(struct net_device *dev, const u32 *indir,
12878c2ecf20Sopenharmony_ci			 const u8 *key, const u8 hfunc)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
12908c2ecf20Sopenharmony_ci	int rc = 0;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	if (hfunc && hfunc != ETH_RSS_HASH_TOP)
12938c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	if (key)
12968c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	if (indir) {
12998c2ecf20Sopenharmony_ci		u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev);
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci		for (i = 0; i < tbl_size; i++)
13028c2ecf20Sopenharmony_ci			bp->rss_indir_tbl[i] = indir[i];
13038c2ecf20Sopenharmony_ci		pad = bp->rss_indir_tbl_entries - tbl_size;
13048c2ecf20Sopenharmony_ci		if (pad)
13058c2ecf20Sopenharmony_ci			memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16));
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	if (netif_running(bp->dev)) {
13098c2ecf20Sopenharmony_ci		bnxt_close_nic(bp, false, false);
13108c2ecf20Sopenharmony_ci		rc = bnxt_open_nic(bp, false, false);
13118c2ecf20Sopenharmony_ci	}
13128c2ecf20Sopenharmony_ci	return rc;
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_cistatic void bnxt_get_drvinfo(struct net_device *dev,
13168c2ecf20Sopenharmony_ci			     struct ethtool_drvinfo *info)
13178c2ecf20Sopenharmony_ci{
13188c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
13218c2ecf20Sopenharmony_ci	strlcpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version));
13228c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
13238c2ecf20Sopenharmony_ci	info->n_stats = bnxt_get_num_stats(bp);
13248c2ecf20Sopenharmony_ci	info->testinfo_len = bp->num_tests;
13258c2ecf20Sopenharmony_ci	/* TODO CHIMP_FW: eeprom dump details */
13268c2ecf20Sopenharmony_ci	info->eedump_len = 0;
13278c2ecf20Sopenharmony_ci	/* TODO CHIMP FW: reg dump details */
13288c2ecf20Sopenharmony_ci	info->regdump_len = 0;
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic int bnxt_get_regs_len(struct net_device *dev)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
13348c2ecf20Sopenharmony_ci	int reg_len;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	if (!BNXT_PF(bp))
13378c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	reg_len = BNXT_PXP_REG_LEN;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	if (bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED)
13428c2ecf20Sopenharmony_ci		reg_len += sizeof(struct pcie_ctx_hw_stats);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	return reg_len;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic void bnxt_get_regs(struct net_device *dev, struct ethtool_regs *regs,
13488c2ecf20Sopenharmony_ci			  void *_p)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	struct pcie_ctx_hw_stats *hw_pcie_stats;
13518c2ecf20Sopenharmony_ci	struct hwrm_pcie_qstats_input req = {0};
13528c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
13538c2ecf20Sopenharmony_ci	dma_addr_t hw_pcie_stats_addr;
13548c2ecf20Sopenharmony_ci	int rc;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	regs->version = 0;
13578c2ecf20Sopenharmony_ci	bnxt_dbg_hwrm_rd_reg(bp, 0, BNXT_PXP_REG_LEN / 4, _p);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if (!(bp->fw_cap & BNXT_FW_CAP_PCIE_STATS_SUPPORTED))
13608c2ecf20Sopenharmony_ci		return;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	hw_pcie_stats = dma_alloc_coherent(&bp->pdev->dev,
13638c2ecf20Sopenharmony_ci					   sizeof(*hw_pcie_stats),
13648c2ecf20Sopenharmony_ci					   &hw_pcie_stats_addr, GFP_KERNEL);
13658c2ecf20Sopenharmony_ci	if (!hw_pcie_stats)
13668c2ecf20Sopenharmony_ci		return;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	regs->version = 1;
13698c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PCIE_QSTATS, -1, -1);
13708c2ecf20Sopenharmony_ci	req.pcie_stat_size = cpu_to_le16(sizeof(*hw_pcie_stats));
13718c2ecf20Sopenharmony_ci	req.pcie_stat_host_addr = cpu_to_le64(hw_pcie_stats_addr);
13728c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
13738c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
13748c2ecf20Sopenharmony_ci	if (!rc) {
13758c2ecf20Sopenharmony_ci		__le64 *src = (__le64 *)hw_pcie_stats;
13768c2ecf20Sopenharmony_ci		u64 *dst = (u64 *)(_p + BNXT_PXP_REG_LEN);
13778c2ecf20Sopenharmony_ci		int i;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci		for (i = 0; i < sizeof(*hw_pcie_stats) / sizeof(__le64); i++)
13808c2ecf20Sopenharmony_ci			dst[i] = le64_to_cpu(src[i]);
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
13838c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, sizeof(*hw_pcie_stats), hw_pcie_stats,
13848c2ecf20Sopenharmony_ci			  hw_pcie_stats_addr);
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cistatic void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	wol->supported = 0;
13928c2ecf20Sopenharmony_ci	wol->wolopts = 0;
13938c2ecf20Sopenharmony_ci	memset(&wol->sopass, 0, sizeof(wol->sopass));
13948c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_WOL_CAP) {
13958c2ecf20Sopenharmony_ci		wol->supported = WAKE_MAGIC;
13968c2ecf20Sopenharmony_ci		if (bp->wol)
13978c2ecf20Sopenharmony_ci			wol->wolopts = WAKE_MAGIC;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	if (wol->wolopts & ~WAKE_MAGIC)
14068c2ecf20Sopenharmony_ci		return -EINVAL;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	if (wol->wolopts & WAKE_MAGIC) {
14098c2ecf20Sopenharmony_ci		if (!(bp->flags & BNXT_FLAG_WOL_CAP))
14108c2ecf20Sopenharmony_ci			return -EINVAL;
14118c2ecf20Sopenharmony_ci		if (!bp->wol) {
14128c2ecf20Sopenharmony_ci			if (bnxt_hwrm_alloc_wol_fltr(bp))
14138c2ecf20Sopenharmony_ci				return -EBUSY;
14148c2ecf20Sopenharmony_ci			bp->wol = 1;
14158c2ecf20Sopenharmony_ci		}
14168c2ecf20Sopenharmony_ci	} else {
14178c2ecf20Sopenharmony_ci		if (bp->wol) {
14188c2ecf20Sopenharmony_ci			if (bnxt_hwrm_free_wol_fltr(bp))
14198c2ecf20Sopenharmony_ci				return -EBUSY;
14208c2ecf20Sopenharmony_ci			bp->wol = 0;
14218c2ecf20Sopenharmony_ci		}
14228c2ecf20Sopenharmony_ci	}
14238c2ecf20Sopenharmony_ci	return 0;
14248c2ecf20Sopenharmony_ci}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ciu32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	u32 speed_mask = 0;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	/* TODO: support 25GB, 40GB, 50GB with different cable type */
14318c2ecf20Sopenharmony_ci	/* set the advertised speeds */
14328c2ecf20Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
14338c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_100baseT_Full;
14348c2ecf20Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
14358c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_1000baseT_Full;
14368c2ecf20Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
14378c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_2500baseX_Full;
14388c2ecf20Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
14398c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_10000baseT_Full;
14408c2ecf20Sopenharmony_ci	if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
14418c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_40000baseCR4_Full;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH)
14448c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_Pause;
14458c2ecf20Sopenharmony_ci	else if (fw_pause & BNXT_LINK_PAUSE_TX)
14468c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_Asym_Pause;
14478c2ecf20Sopenharmony_ci	else if (fw_pause & BNXT_LINK_PAUSE_RX)
14488c2ecf20Sopenharmony_ci		speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	return speed_mask;
14518c2ecf20Sopenharmony_ci}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\
14548c2ecf20Sopenharmony_ci{									\
14558c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB)			\
14568c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14578c2ecf20Sopenharmony_ci						     100baseT_Full);	\
14588c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB)			\
14598c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14608c2ecf20Sopenharmony_ci						     1000baseT_Full);	\
14618c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB)			\
14628c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14638c2ecf20Sopenharmony_ci						     10000baseT_Full);	\
14648c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB)			\
14658c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14668c2ecf20Sopenharmony_ci						     25000baseCR_Full);	\
14678c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB)			\
14688c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14698c2ecf20Sopenharmony_ci						     40000baseCR4_Full);\
14708c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB)			\
14718c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14728c2ecf20Sopenharmony_ci						     50000baseCR2_Full);\
14738c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100GB)			\
14748c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14758c2ecf20Sopenharmony_ci						     100000baseCR4_Full);\
14768c2ecf20Sopenharmony_ci	if ((fw_pause) & BNXT_LINK_PAUSE_RX) {				\
14778c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14788c2ecf20Sopenharmony_ci						     Pause);		\
14798c2ecf20Sopenharmony_ci		if (!((fw_pause) & BNXT_LINK_PAUSE_TX))			\
14808c2ecf20Sopenharmony_ci			ethtool_link_ksettings_add_link_mode(		\
14818c2ecf20Sopenharmony_ci					lk_ksettings, name, Asym_Pause);\
14828c2ecf20Sopenharmony_ci	} else if ((fw_pause) & BNXT_LINK_PAUSE_TX) {			\
14838c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
14848c2ecf20Sopenharmony_ci						     Asym_Pause);	\
14858c2ecf20Sopenharmony_ci	}								\
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name)		\
14898c2ecf20Sopenharmony_ci{									\
14908c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
14918c2ecf20Sopenharmony_ci						  100baseT_Full) ||	\
14928c2ecf20Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
14938c2ecf20Sopenharmony_ci						  100baseT_Half))	\
14948c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB;		\
14958c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
14968c2ecf20Sopenharmony_ci						  1000baseT_Full) ||	\
14978c2ecf20Sopenharmony_ci	    ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
14988c2ecf20Sopenharmony_ci						  1000baseT_Half))	\
14998c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB;			\
15008c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15018c2ecf20Sopenharmony_ci						  10000baseT_Full))	\
15028c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB;		\
15038c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15048c2ecf20Sopenharmony_ci						  25000baseCR_Full))	\
15058c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB;		\
15068c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15078c2ecf20Sopenharmony_ci						  40000baseCR4_Full))	\
15088c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB;		\
15098c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15108c2ecf20Sopenharmony_ci						  50000baseCR2_Full))	\
15118c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB;		\
15128c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15138c2ecf20Sopenharmony_ci						  100000baseCR4_Full))	\
15148c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_SPEED_MSK_100GB;		\
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci#define BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, name)	\
15188c2ecf20Sopenharmony_ci{									\
15198c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_50GB)		\
15208c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
15218c2ecf20Sopenharmony_ci						     50000baseCR_Full);	\
15228c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_100GB)		\
15238c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
15248c2ecf20Sopenharmony_ci						     100000baseCR2_Full);\
15258c2ecf20Sopenharmony_ci	if ((fw_speeds) & BNXT_LINK_PAM4_SPEED_MSK_200GB)		\
15268c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
15278c2ecf20Sopenharmony_ci						     200000baseCR4_Full);\
15288c2ecf20Sopenharmony_ci}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci#define BNXT_ETHTOOL_TO_FW_PAM4_SPDS(fw_speeds, lk_ksettings, name)	\
15318c2ecf20Sopenharmony_ci{									\
15328c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15338c2ecf20Sopenharmony_ci						  50000baseCR_Full))	\
15348c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_50GB;		\
15358c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15368c2ecf20Sopenharmony_ci						  100000baseCR2_Full))	\
15378c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_100GB;		\
15388c2ecf20Sopenharmony_ci	if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name,	\
15398c2ecf20Sopenharmony_ci						  200000baseCR4_Full))	\
15408c2ecf20Sopenharmony_ci		(fw_speeds) |= BNXT_LINK_PAM4_SPEED_MSK_200GB;		\
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_fec(struct bnxt_link_info *link_info,
15448c2ecf20Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	u16 fec_cfg = link_info->fec_cfg;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	if ((fec_cfg & BNXT_FEC_NONE) || !(fec_cfg & BNXT_FEC_AUTONEG)) {
15498c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
15508c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
15518c2ecf20Sopenharmony_ci		return;
15528c2ecf20Sopenharmony_ci	}
15538c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_BASE_R)
15548c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
15558c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
15568c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_RS)
15578c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
15588c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
15598c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_LLRS)
15608c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
15618c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.advertising);
15628c2ecf20Sopenharmony_ci}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info,
15658c2ecf20Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
15668c2ecf20Sopenharmony_ci{
15678c2ecf20Sopenharmony_ci	u16 fw_speeds = link_info->advertising;
15688c2ecf20Sopenharmony_ci	u8 fw_pause = 0;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
15718c2ecf20Sopenharmony_ci		fw_pause = link_info->auto_pause_setting;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising);
15748c2ecf20Sopenharmony_ci	fw_speeds = link_info->advertising_pam4;
15758c2ecf20Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, advertising);
15768c2ecf20Sopenharmony_ci	bnxt_fw_to_ethtool_advertised_fec(link_info, lk_ksettings);
15778c2ecf20Sopenharmony_ci}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info,
15808c2ecf20Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
15818c2ecf20Sopenharmony_ci{
15828c2ecf20Sopenharmony_ci	u16 fw_speeds = link_info->lp_auto_link_speeds;
15838c2ecf20Sopenharmony_ci	u8 fw_pause = 0;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
15868c2ecf20Sopenharmony_ci		fw_pause = link_info->lp_pause;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings,
15898c2ecf20Sopenharmony_ci				lp_advertising);
15908c2ecf20Sopenharmony_ci	fw_speeds = link_info->lp_auto_pam4_link_speeds;
15918c2ecf20Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, lp_advertising);
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_fec(struct bnxt_link_info *link_info,
15958c2ecf20Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
15968c2ecf20Sopenharmony_ci{
15978c2ecf20Sopenharmony_ci	u16 fec_cfg = link_info->fec_cfg;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_NONE) {
16008c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
16018c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.supported);
16028c2ecf20Sopenharmony_ci		return;
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_BASE_R_CAP)
16058c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
16068c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.supported);
16078c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_RS_CAP)
16088c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
16098c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.supported);
16108c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_LLRS_CAP)
16118c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
16128c2ecf20Sopenharmony_ci				 lk_ksettings->link_modes.supported);
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_cistatic void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info,
16168c2ecf20Sopenharmony_ci				struct ethtool_link_ksettings *lk_ksettings)
16178c2ecf20Sopenharmony_ci{
16188c2ecf20Sopenharmony_ci	u16 fw_speeds = link_info->support_speeds;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported);
16218c2ecf20Sopenharmony_ci	fw_speeds = link_info->support_pam4_speeds;
16228c2ecf20Sopenharmony_ci	BNXT_FW_TO_ETHTOOL_PAM4_SPDS(fw_speeds, lk_ksettings, supported);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause);
16258c2ecf20Sopenharmony_ci	ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
16268c2ecf20Sopenharmony_ci					     Asym_Pause);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (link_info->support_auto_speeds ||
16298c2ecf20Sopenharmony_ci	    link_info->support_pam4_auto_speeds)
16308c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
16318c2ecf20Sopenharmony_ci						     Autoneg);
16328c2ecf20Sopenharmony_ci	bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings);
16338c2ecf20Sopenharmony_ci}
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ciu32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	switch (fw_link_speed) {
16388c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_100MB:
16398c2ecf20Sopenharmony_ci		return SPEED_100;
16408c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_1GB:
16418c2ecf20Sopenharmony_ci		return SPEED_1000;
16428c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_2_5GB:
16438c2ecf20Sopenharmony_ci		return SPEED_2500;
16448c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_10GB:
16458c2ecf20Sopenharmony_ci		return SPEED_10000;
16468c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_20GB:
16478c2ecf20Sopenharmony_ci		return SPEED_20000;
16488c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_25GB:
16498c2ecf20Sopenharmony_ci		return SPEED_25000;
16508c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_40GB:
16518c2ecf20Sopenharmony_ci		return SPEED_40000;
16528c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_50GB:
16538c2ecf20Sopenharmony_ci		return SPEED_50000;
16548c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_100GB:
16558c2ecf20Sopenharmony_ci		return SPEED_100000;
16568c2ecf20Sopenharmony_ci	case BNXT_LINK_SPEED_200GB:
16578c2ecf20Sopenharmony_ci		return SPEED_200000;
16588c2ecf20Sopenharmony_ci	default:
16598c2ecf20Sopenharmony_ci		return SPEED_UNKNOWN;
16608c2ecf20Sopenharmony_ci	}
16618c2ecf20Sopenharmony_ci}
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_cistatic int bnxt_get_link_ksettings(struct net_device *dev,
16648c2ecf20Sopenharmony_ci				   struct ethtool_link_ksettings *lk_ksettings)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
16678c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
16688c2ecf20Sopenharmony_ci	struct ethtool_link_settings *base = &lk_ksettings->base;
16698c2ecf20Sopenharmony_ci	u32 ethtool_speed;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported);
16728c2ecf20Sopenharmony_ci	mutex_lock(&bp->link_lock);
16738c2ecf20Sopenharmony_ci	bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings);
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising);
16768c2ecf20Sopenharmony_ci	if (link_info->autoneg) {
16778c2ecf20Sopenharmony_ci		bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings);
16788c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings,
16798c2ecf20Sopenharmony_ci						     advertising, Autoneg);
16808c2ecf20Sopenharmony_ci		base->autoneg = AUTONEG_ENABLE;
16818c2ecf20Sopenharmony_ci		base->duplex = DUPLEX_UNKNOWN;
16828c2ecf20Sopenharmony_ci		if (link_info->phy_link_status == BNXT_LINK_LINK) {
16838c2ecf20Sopenharmony_ci			bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings);
16848c2ecf20Sopenharmony_ci			if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
16858c2ecf20Sopenharmony_ci				base->duplex = DUPLEX_FULL;
16868c2ecf20Sopenharmony_ci			else
16878c2ecf20Sopenharmony_ci				base->duplex = DUPLEX_HALF;
16888c2ecf20Sopenharmony_ci		}
16898c2ecf20Sopenharmony_ci		ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
16908c2ecf20Sopenharmony_ci	} else {
16918c2ecf20Sopenharmony_ci		base->autoneg = AUTONEG_DISABLE;
16928c2ecf20Sopenharmony_ci		ethtool_speed =
16938c2ecf20Sopenharmony_ci			bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
16948c2ecf20Sopenharmony_ci		base->duplex = DUPLEX_HALF;
16958c2ecf20Sopenharmony_ci		if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL)
16968c2ecf20Sopenharmony_ci			base->duplex = DUPLEX_FULL;
16978c2ecf20Sopenharmony_ci	}
16988c2ecf20Sopenharmony_ci	base->speed = ethtool_speed;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	base->port = PORT_NONE;
17018c2ecf20Sopenharmony_ci	if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
17028c2ecf20Sopenharmony_ci		base->port = PORT_TP;
17038c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
17048c2ecf20Sopenharmony_ci						     TP);
17058c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
17068c2ecf20Sopenharmony_ci						     TP);
17078c2ecf20Sopenharmony_ci	} else {
17088c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
17098c2ecf20Sopenharmony_ci						     FIBRE);
17108c2ecf20Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
17118c2ecf20Sopenharmony_ci						     FIBRE);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci		if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
17148c2ecf20Sopenharmony_ci			base->port = PORT_DA;
17158c2ecf20Sopenharmony_ci		else if (link_info->media_type ==
17168c2ecf20Sopenharmony_ci			 PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
17178c2ecf20Sopenharmony_ci			base->port = PORT_FIBRE;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci	base->phy_address = link_info->phy_addr;
17208c2ecf20Sopenharmony_ci	mutex_unlock(&bp->link_lock);
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	return 0;
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic int bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed)
17268c2ecf20Sopenharmony_ci{
17278c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
17288c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
17298c2ecf20Sopenharmony_ci	u16 support_pam4_spds = link_info->support_pam4_speeds;
17308c2ecf20Sopenharmony_ci	u16 support_spds = link_info->support_speeds;
17318c2ecf20Sopenharmony_ci	u8 sig_mode = BNXT_SIG_MODE_NRZ;
17328c2ecf20Sopenharmony_ci	u16 fw_speed = 0;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	switch (ethtool_speed) {
17358c2ecf20Sopenharmony_ci	case SPEED_100:
17368c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_100MB)
17378c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB;
17388c2ecf20Sopenharmony_ci		break;
17398c2ecf20Sopenharmony_ci	case SPEED_1000:
17408c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_1GB)
17418c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
17428c2ecf20Sopenharmony_ci		break;
17438c2ecf20Sopenharmony_ci	case SPEED_2500:
17448c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB)
17458c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB;
17468c2ecf20Sopenharmony_ci		break;
17478c2ecf20Sopenharmony_ci	case SPEED_10000:
17488c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_10GB)
17498c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
17508c2ecf20Sopenharmony_ci		break;
17518c2ecf20Sopenharmony_ci	case SPEED_20000:
17528c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_20GB)
17538c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_20GB;
17548c2ecf20Sopenharmony_ci		break;
17558c2ecf20Sopenharmony_ci	case SPEED_25000:
17568c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_25GB)
17578c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
17588c2ecf20Sopenharmony_ci		break;
17598c2ecf20Sopenharmony_ci	case SPEED_40000:
17608c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_40GB)
17618c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
17628c2ecf20Sopenharmony_ci		break;
17638c2ecf20Sopenharmony_ci	case SPEED_50000:
17648c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_50GB) {
17658c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
17668c2ecf20Sopenharmony_ci		} else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) {
17678c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB;
17688c2ecf20Sopenharmony_ci			sig_mode = BNXT_SIG_MODE_PAM4;
17698c2ecf20Sopenharmony_ci		}
17708c2ecf20Sopenharmony_ci		break;
17718c2ecf20Sopenharmony_ci	case SPEED_100000:
17728c2ecf20Sopenharmony_ci		if (support_spds & BNXT_LINK_SPEED_MSK_100GB) {
17738c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB;
17748c2ecf20Sopenharmony_ci		} else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_100GB) {
17758c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB;
17768c2ecf20Sopenharmony_ci			sig_mode = BNXT_SIG_MODE_PAM4;
17778c2ecf20Sopenharmony_ci		}
17788c2ecf20Sopenharmony_ci		break;
17798c2ecf20Sopenharmony_ci	case SPEED_200000:
17808c2ecf20Sopenharmony_ci		if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_200GB) {
17818c2ecf20Sopenharmony_ci			fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB;
17828c2ecf20Sopenharmony_ci			sig_mode = BNXT_SIG_MODE_PAM4;
17838c2ecf20Sopenharmony_ci		}
17848c2ecf20Sopenharmony_ci		break;
17858c2ecf20Sopenharmony_ci	}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (!fw_speed) {
17888c2ecf20Sopenharmony_ci		netdev_err(dev, "unsupported speed!\n");
17898c2ecf20Sopenharmony_ci		return -EINVAL;
17908c2ecf20Sopenharmony_ci	}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	if (link_info->req_link_speed == fw_speed &&
17938c2ecf20Sopenharmony_ci	    link_info->req_signal_mode == sig_mode &&
17948c2ecf20Sopenharmony_ci	    link_info->autoneg == 0)
17958c2ecf20Sopenharmony_ci		return -EALREADY;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	link_info->req_link_speed = fw_speed;
17988c2ecf20Sopenharmony_ci	link_info->req_signal_mode = sig_mode;
17998c2ecf20Sopenharmony_ci	link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
18008c2ecf20Sopenharmony_ci	link_info->autoneg = 0;
18018c2ecf20Sopenharmony_ci	link_info->advertising = 0;
18028c2ecf20Sopenharmony_ci	link_info->advertising_pam4 = 0;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	return 0;
18058c2ecf20Sopenharmony_ci}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ciu16 bnxt_get_fw_auto_link_speeds(u32 advertising)
18088c2ecf20Sopenharmony_ci{
18098c2ecf20Sopenharmony_ci	u16 fw_speed_mask = 0;
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	/* only support autoneg at speed 100, 1000, and 10000 */
18128c2ecf20Sopenharmony_ci	if (advertising & (ADVERTISED_100baseT_Full |
18138c2ecf20Sopenharmony_ci			   ADVERTISED_100baseT_Half)) {
18148c2ecf20Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB;
18158c2ecf20Sopenharmony_ci	}
18168c2ecf20Sopenharmony_ci	if (advertising & (ADVERTISED_1000baseT_Full |
18178c2ecf20Sopenharmony_ci			   ADVERTISED_1000baseT_Half)) {
18188c2ecf20Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB;
18198c2ecf20Sopenharmony_ci	}
18208c2ecf20Sopenharmony_ci	if (advertising & ADVERTISED_10000baseT_Full)
18218c2ecf20Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	if (advertising & ADVERTISED_40000baseCR4_Full)
18248c2ecf20Sopenharmony_ci		fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	return fw_speed_mask;
18278c2ecf20Sopenharmony_ci}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_cistatic int bnxt_set_link_ksettings(struct net_device *dev,
18308c2ecf20Sopenharmony_ci			   const struct ethtool_link_ksettings *lk_ksettings)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
18338c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
18348c2ecf20Sopenharmony_ci	const struct ethtool_link_settings *base = &lk_ksettings->base;
18358c2ecf20Sopenharmony_ci	bool set_pause = false;
18368c2ecf20Sopenharmony_ci	u32 speed;
18378c2ecf20Sopenharmony_ci	int rc = 0;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
18408c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	mutex_lock(&bp->link_lock);
18438c2ecf20Sopenharmony_ci	if (base->autoneg == AUTONEG_ENABLE) {
18448c2ecf20Sopenharmony_ci		link_info->advertising = 0;
18458c2ecf20Sopenharmony_ci		link_info->advertising_pam4 = 0;
18468c2ecf20Sopenharmony_ci		BNXT_ETHTOOL_TO_FW_SPDS(link_info->advertising, lk_ksettings,
18478c2ecf20Sopenharmony_ci					advertising);
18488c2ecf20Sopenharmony_ci		BNXT_ETHTOOL_TO_FW_PAM4_SPDS(link_info->advertising_pam4,
18498c2ecf20Sopenharmony_ci					     lk_ksettings, advertising);
18508c2ecf20Sopenharmony_ci		link_info->autoneg |= BNXT_AUTONEG_SPEED;
18518c2ecf20Sopenharmony_ci		if (!link_info->advertising && !link_info->advertising_pam4) {
18528c2ecf20Sopenharmony_ci			link_info->advertising = link_info->support_auto_speeds;
18538c2ecf20Sopenharmony_ci			link_info->advertising_pam4 =
18548c2ecf20Sopenharmony_ci				link_info->support_pam4_auto_speeds;
18558c2ecf20Sopenharmony_ci		}
18568c2ecf20Sopenharmony_ci		/* any change to autoneg will cause link change, therefore the
18578c2ecf20Sopenharmony_ci		 * driver should put back the original pause setting in autoneg
18588c2ecf20Sopenharmony_ci		 */
18598c2ecf20Sopenharmony_ci		set_pause = true;
18608c2ecf20Sopenharmony_ci	} else {
18618c2ecf20Sopenharmony_ci		u8 phy_type = link_info->phy_type;
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci		if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET  ||
18648c2ecf20Sopenharmony_ci		    phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE ||
18658c2ecf20Sopenharmony_ci		    link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
18668c2ecf20Sopenharmony_ci			netdev_err(dev, "10GBase-T devices must autoneg\n");
18678c2ecf20Sopenharmony_ci			rc = -EINVAL;
18688c2ecf20Sopenharmony_ci			goto set_setting_exit;
18698c2ecf20Sopenharmony_ci		}
18708c2ecf20Sopenharmony_ci		if (base->duplex == DUPLEX_HALF) {
18718c2ecf20Sopenharmony_ci			netdev_err(dev, "HALF DUPLEX is not supported!\n");
18728c2ecf20Sopenharmony_ci			rc = -EINVAL;
18738c2ecf20Sopenharmony_ci			goto set_setting_exit;
18748c2ecf20Sopenharmony_ci		}
18758c2ecf20Sopenharmony_ci		speed = base->speed;
18768c2ecf20Sopenharmony_ci		rc = bnxt_force_link_speed(dev, speed);
18778c2ecf20Sopenharmony_ci		if (rc) {
18788c2ecf20Sopenharmony_ci			if (rc == -EALREADY)
18798c2ecf20Sopenharmony_ci				rc = 0;
18808c2ecf20Sopenharmony_ci			goto set_setting_exit;
18818c2ecf20Sopenharmony_ci		}
18828c2ecf20Sopenharmony_ci	}
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	if (netif_running(dev))
18858c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_set_link_setting(bp, set_pause, false);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ciset_setting_exit:
18888c2ecf20Sopenharmony_ci	mutex_unlock(&bp->link_lock);
18898c2ecf20Sopenharmony_ci	return rc;
18908c2ecf20Sopenharmony_ci}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_cistatic int bnxt_get_fecparam(struct net_device *dev,
18938c2ecf20Sopenharmony_ci			     struct ethtool_fecparam *fec)
18948c2ecf20Sopenharmony_ci{
18958c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
18968c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info;
18978c2ecf20Sopenharmony_ci	u8 active_fec;
18988c2ecf20Sopenharmony_ci	u16 fec_cfg;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	link_info = &bp->link_info;
19018c2ecf20Sopenharmony_ci	fec_cfg = link_info->fec_cfg;
19028c2ecf20Sopenharmony_ci	active_fec = link_info->active_fec_sig_mode &
19038c2ecf20Sopenharmony_ci		     PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK;
19048c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_NONE) {
19058c2ecf20Sopenharmony_ci		fec->fec = ETHTOOL_FEC_NONE;
19068c2ecf20Sopenharmony_ci		fec->active_fec = ETHTOOL_FEC_NONE;
19078c2ecf20Sopenharmony_ci		return 0;
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_AUTONEG)
19108c2ecf20Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_AUTO;
19118c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_BASE_R)
19128c2ecf20Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_BASER;
19138c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_RS)
19148c2ecf20Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_RS;
19158c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_ENC_LLRS)
19168c2ecf20Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_LLRS;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	switch (active_fec) {
19198c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE:
19208c2ecf20Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_BASER;
19218c2ecf20Sopenharmony_ci		break;
19228c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE:
19238c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE:
19248c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE:
19258c2ecf20Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_RS;
19268c2ecf20Sopenharmony_ci		break;
19278c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE:
19288c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE:
19298c2ecf20Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_LLRS;
19308c2ecf20Sopenharmony_ci		break;
19318c2ecf20Sopenharmony_ci	case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE:
19328c2ecf20Sopenharmony_ci		fec->active_fec |= ETHTOOL_FEC_OFF;
19338c2ecf20Sopenharmony_ci		break;
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci	return 0;
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_cistatic u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info,
19398c2ecf20Sopenharmony_ci					 u32 fec)
19408c2ecf20Sopenharmony_ci{
19418c2ecf20Sopenharmony_ci	u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	if (fec & ETHTOOL_FEC_BASER)
19448c2ecf20Sopenharmony_ci		fw_fec |= BNXT_FEC_BASE_R_ON(link_info);
19458c2ecf20Sopenharmony_ci	else if (fec & ETHTOOL_FEC_RS)
19468c2ecf20Sopenharmony_ci		fw_fec |= BNXT_FEC_RS_ON(link_info);
19478c2ecf20Sopenharmony_ci	else if (fec & ETHTOOL_FEC_LLRS)
19488c2ecf20Sopenharmony_ci		fw_fec |= BNXT_FEC_LLRS_ON;
19498c2ecf20Sopenharmony_ci	return fw_fec;
19508c2ecf20Sopenharmony_ci}
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_cistatic int bnxt_set_fecparam(struct net_device *dev,
19538c2ecf20Sopenharmony_ci			     struct ethtool_fecparam *fecparam)
19548c2ecf20Sopenharmony_ci{
19558c2ecf20Sopenharmony_ci	struct hwrm_port_phy_cfg_input req = {0};
19568c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
19578c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info;
19588c2ecf20Sopenharmony_ci	u32 new_cfg, fec = fecparam->fec;
19598c2ecf20Sopenharmony_ci	u16 fec_cfg;
19608c2ecf20Sopenharmony_ci	int rc;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	link_info = &bp->link_info;
19638c2ecf20Sopenharmony_ci	fec_cfg = link_info->fec_cfg;
19648c2ecf20Sopenharmony_ci	if (fec_cfg & BNXT_FEC_NONE)
19658c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	if (fec & ETHTOOL_FEC_OFF) {
19688c2ecf20Sopenharmony_ci		new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE |
19698c2ecf20Sopenharmony_ci			  BNXT_FEC_ALL_OFF(link_info);
19708c2ecf20Sopenharmony_ci		goto apply_fec;
19718c2ecf20Sopenharmony_ci	}
19728c2ecf20Sopenharmony_ci	if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) ||
19738c2ecf20Sopenharmony_ci	    ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) ||
19748c2ecf20Sopenharmony_ci	    ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) ||
19758c2ecf20Sopenharmony_ci	    ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP)))
19768c2ecf20Sopenharmony_ci		return -EINVAL;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (fec & ETHTOOL_FEC_AUTO) {
19798c2ecf20Sopenharmony_ci		if (!link_info->autoneg)
19808c2ecf20Sopenharmony_ci			return -EINVAL;
19818c2ecf20Sopenharmony_ci		new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE;
19828c2ecf20Sopenharmony_ci	} else {
19838c2ecf20Sopenharmony_ci		new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec);
19848c2ecf20Sopenharmony_ci	}
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ciapply_fec:
19878c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1);
19888c2ecf20Sopenharmony_ci	req.flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
19898c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
19908c2ecf20Sopenharmony_ci	/* update current settings */
19918c2ecf20Sopenharmony_ci	if (!rc) {
19928c2ecf20Sopenharmony_ci		mutex_lock(&bp->link_lock);
19938c2ecf20Sopenharmony_ci		bnxt_update_link(bp, false);
19948c2ecf20Sopenharmony_ci		mutex_unlock(&bp->link_lock);
19958c2ecf20Sopenharmony_ci	}
19968c2ecf20Sopenharmony_ci	return rc;
19978c2ecf20Sopenharmony_ci}
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_cistatic void bnxt_get_pauseparam(struct net_device *dev,
20008c2ecf20Sopenharmony_ci				struct ethtool_pauseparam *epause)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
20038c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	if (BNXT_VF(bp))
20068c2ecf20Sopenharmony_ci		return;
20078c2ecf20Sopenharmony_ci	epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL);
20088c2ecf20Sopenharmony_ci	epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX);
20098c2ecf20Sopenharmony_ci	epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX);
20108c2ecf20Sopenharmony_ci}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_cistatic void bnxt_get_pause_stats(struct net_device *dev,
20138c2ecf20Sopenharmony_ci				 struct ethtool_pause_stats *epstat)
20148c2ecf20Sopenharmony_ci{
20158c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
20168c2ecf20Sopenharmony_ci	u64 *rx, *tx;
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
20198c2ecf20Sopenharmony_ci		return;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	rx = bp->port_stats.sw_stats;
20228c2ecf20Sopenharmony_ci	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	epstat->rx_pause_frames = BNXT_GET_RX_PORT_STATS64(rx, rx_pause_frames);
20258c2ecf20Sopenharmony_ci	epstat->tx_pause_frames = BNXT_GET_TX_PORT_STATS64(tx, tx_pause_frames);
20268c2ecf20Sopenharmony_ci}
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_cistatic int bnxt_set_pauseparam(struct net_device *dev,
20298c2ecf20Sopenharmony_ci			       struct ethtool_pauseparam *epause)
20308c2ecf20Sopenharmony_ci{
20318c2ecf20Sopenharmony_ci	int rc = 0;
20328c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
20338c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
20368c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	mutex_lock(&bp->link_lock);
20398c2ecf20Sopenharmony_ci	if (epause->autoneg) {
20408c2ecf20Sopenharmony_ci		if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
20418c2ecf20Sopenharmony_ci			rc = -EINVAL;
20428c2ecf20Sopenharmony_ci			goto pause_exit;
20438c2ecf20Sopenharmony_ci		}
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci		link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
20468c2ecf20Sopenharmony_ci		link_info->req_flow_ctrl = 0;
20478c2ecf20Sopenharmony_ci	} else {
20488c2ecf20Sopenharmony_ci		/* when transition from auto pause to force pause,
20498c2ecf20Sopenharmony_ci		 * force a link change
20508c2ecf20Sopenharmony_ci		 */
20518c2ecf20Sopenharmony_ci		if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
20528c2ecf20Sopenharmony_ci			link_info->force_link_chng = true;
20538c2ecf20Sopenharmony_ci		link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL;
20548c2ecf20Sopenharmony_ci		link_info->req_flow_ctrl = 0;
20558c2ecf20Sopenharmony_ci	}
20568c2ecf20Sopenharmony_ci	if (epause->rx_pause)
20578c2ecf20Sopenharmony_ci		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	if (epause->tx_pause)
20608c2ecf20Sopenharmony_ci		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	if (netif_running(dev))
20638c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_set_pause(bp);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_cipause_exit:
20668c2ecf20Sopenharmony_ci	mutex_unlock(&bp->link_lock);
20678c2ecf20Sopenharmony_ci	return rc;
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_cistatic u32 bnxt_get_link(struct net_device *dev)
20718c2ecf20Sopenharmony_ci{
20728c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	/* TODO: handle MF, VF, driver close case */
20758c2ecf20Sopenharmony_ci	return bp->link_info.link_up;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ciint bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp,
20798c2ecf20Sopenharmony_ci			       struct hwrm_nvm_get_dev_info_output *nvm_dev_info)
20808c2ecf20Sopenharmony_ci{
20818c2ecf20Sopenharmony_ci	struct hwrm_nvm_get_dev_info_output *resp = bp->hwrm_cmd_resp_addr;
20828c2ecf20Sopenharmony_ci	struct hwrm_nvm_get_dev_info_input req = {0};
20838c2ecf20Sopenharmony_ci	int rc;
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	if (BNXT_VF(bp))
20868c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DEV_INFO, -1, -1);
20898c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
20908c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
20918c2ecf20Sopenharmony_ci	if (!rc)
20928c2ecf20Sopenharmony_ci		memcpy(nvm_dev_info, resp, sizeof(*resp));
20938c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
20948c2ecf20Sopenharmony_ci	return rc;
20958c2ecf20Sopenharmony_ci}
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_cistatic void bnxt_print_admin_err(struct bnxt *bp)
20988c2ecf20Sopenharmony_ci{
20998c2ecf20Sopenharmony_ci	netdev_info(bp->dev, "PF does not have admin privileges to flash or reset the device\n");
21008c2ecf20Sopenharmony_ci}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_cistatic int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
21038c2ecf20Sopenharmony_ci				u16 ext, u16 *index, u32 *item_length,
21048c2ecf20Sopenharmony_ci				u32 *data_length);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_cistatic int bnxt_flash_nvram(struct net_device *dev,
21078c2ecf20Sopenharmony_ci			    u16 dir_type,
21088c2ecf20Sopenharmony_ci			    u16 dir_ordinal,
21098c2ecf20Sopenharmony_ci			    u16 dir_ext,
21108c2ecf20Sopenharmony_ci			    u16 dir_attr,
21118c2ecf20Sopenharmony_ci			    const u8 *data,
21128c2ecf20Sopenharmony_ci			    size_t data_len)
21138c2ecf20Sopenharmony_ci{
21148c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
21158c2ecf20Sopenharmony_ci	int rc;
21168c2ecf20Sopenharmony_ci	struct hwrm_nvm_write_input req = {0};
21178c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
21188c2ecf20Sopenharmony_ci	u8 *kmem;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_WRITE, -1, -1);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	req.dir_type = cpu_to_le16(dir_type);
21238c2ecf20Sopenharmony_ci	req.dir_ordinal = cpu_to_le16(dir_ordinal);
21248c2ecf20Sopenharmony_ci	req.dir_ext = cpu_to_le16(dir_ext);
21258c2ecf20Sopenharmony_ci	req.dir_attr = cpu_to_le16(dir_attr);
21268c2ecf20Sopenharmony_ci	req.dir_data_length = cpu_to_le32(data_len);
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle,
21298c2ecf20Sopenharmony_ci				  GFP_KERNEL);
21308c2ecf20Sopenharmony_ci	if (!kmem) {
21318c2ecf20Sopenharmony_ci		netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
21328c2ecf20Sopenharmony_ci			   (unsigned)data_len);
21338c2ecf20Sopenharmony_ci		return -ENOMEM;
21348c2ecf20Sopenharmony_ci	}
21358c2ecf20Sopenharmony_ci	memcpy(kmem, data, data_len);
21368c2ecf20Sopenharmony_ci	req.host_src_addr = cpu_to_le64(dma_handle);
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT);
21398c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle);
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	if (rc == -EACCES)
21428c2ecf20Sopenharmony_ci		bnxt_print_admin_err(bp);
21438c2ecf20Sopenharmony_ci	return rc;
21448c2ecf20Sopenharmony_ci}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_cistatic int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
21478c2ecf20Sopenharmony_ci				    u8 self_reset, u8 flags)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	struct hwrm_fw_reset_input req = {0};
21508c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
21518c2ecf20Sopenharmony_ci	int rc;
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FW_RESET, -1, -1);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	req.embedded_proc_type = proc_type;
21568c2ecf20Sopenharmony_ci	req.selfrst_status = self_reset;
21578c2ecf20Sopenharmony_ci	req.flags = flags;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	if (proc_type == FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP) {
21608c2ecf20Sopenharmony_ci		rc = hwrm_send_message_silent(bp, &req, sizeof(req),
21618c2ecf20Sopenharmony_ci					      HWRM_CMD_TIMEOUT);
21628c2ecf20Sopenharmony_ci	} else {
21638c2ecf20Sopenharmony_ci		rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
21648c2ecf20Sopenharmony_ci		if (rc == -EACCES)
21658c2ecf20Sopenharmony_ci			bnxt_print_admin_err(bp);
21668c2ecf20Sopenharmony_ci	}
21678c2ecf20Sopenharmony_ci	return rc;
21688c2ecf20Sopenharmony_ci}
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_cistatic int bnxt_firmware_reset(struct net_device *dev,
21718c2ecf20Sopenharmony_ci			       enum bnxt_nvm_directory_type dir_type)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	u8 self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE;
21748c2ecf20Sopenharmony_ci	u8 proc_type, flags = 0;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	/* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */
21778c2ecf20Sopenharmony_ci	/*       (e.g. when firmware isn't already running) */
21788c2ecf20Sopenharmony_ci	switch (dir_type) {
21798c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_CHIMP_PATCH:
21808c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE:
21818c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE_2:
21828c2ecf20Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT;
21838c2ecf20Sopenharmony_ci		/* Self-reset ChiMP upon next PCIe reset: */
21848c2ecf20Sopenharmony_ci		self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
21858c2ecf20Sopenharmony_ci		break;
21868c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_APE_FW:
21878c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_APE_PATCH:
21888c2ecf20Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT;
21898c2ecf20Sopenharmony_ci		/* Self-reset APE upon next PCIe reset: */
21908c2ecf20Sopenharmony_ci		self_reset = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
21918c2ecf20Sopenharmony_ci		break;
21928c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_KONG_FW:
21938c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_KONG_PATCH:
21948c2ecf20Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL;
21958c2ecf20Sopenharmony_ci		break;
21968c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BONO_FW:
21978c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BONO_PATCH:
21988c2ecf20Sopenharmony_ci		proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE;
21998c2ecf20Sopenharmony_ci		break;
22008c2ecf20Sopenharmony_ci	default:
22018c2ecf20Sopenharmony_ci		return -EINVAL;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	return bnxt_hwrm_firmware_reset(dev, proc_type, self_reset, flags);
22058c2ecf20Sopenharmony_ci}
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_cistatic int bnxt_firmware_reset_chip(struct net_device *dev)
22088c2ecf20Sopenharmony_ci{
22098c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
22108c2ecf20Sopenharmony_ci	u8 flags = 0;
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET)
22138c2ecf20Sopenharmony_ci		flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL;
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	return bnxt_hwrm_firmware_reset(dev,
22168c2ecf20Sopenharmony_ci					FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP,
22178c2ecf20Sopenharmony_ci					FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP,
22188c2ecf20Sopenharmony_ci					flags);
22198c2ecf20Sopenharmony_ci}
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_cistatic int bnxt_firmware_reset_ap(struct net_device *dev)
22228c2ecf20Sopenharmony_ci{
22238c2ecf20Sopenharmony_ci	return bnxt_hwrm_firmware_reset(dev, FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP,
22248c2ecf20Sopenharmony_ci					FW_RESET_REQ_SELFRST_STATUS_SELFRSTNONE,
22258c2ecf20Sopenharmony_ci					0);
22268c2ecf20Sopenharmony_ci}
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_cistatic int bnxt_flash_firmware(struct net_device *dev,
22298c2ecf20Sopenharmony_ci			       u16 dir_type,
22308c2ecf20Sopenharmony_ci			       const u8 *fw_data,
22318c2ecf20Sopenharmony_ci			       size_t fw_size)
22328c2ecf20Sopenharmony_ci{
22338c2ecf20Sopenharmony_ci	int	rc = 0;
22348c2ecf20Sopenharmony_ci	u16	code_type;
22358c2ecf20Sopenharmony_ci	u32	stored_crc;
22368c2ecf20Sopenharmony_ci	u32	calculated_crc;
22378c2ecf20Sopenharmony_ci	struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data;
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	switch (dir_type) {
22408c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE:
22418c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE_2:
22428c2ecf20Sopenharmony_ci		code_type = CODE_BOOT;
22438c2ecf20Sopenharmony_ci		break;
22448c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_CHIMP_PATCH:
22458c2ecf20Sopenharmony_ci		code_type = CODE_CHIMP_PATCH;
22468c2ecf20Sopenharmony_ci		break;
22478c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_APE_FW:
22488c2ecf20Sopenharmony_ci		code_type = CODE_MCTP_PASSTHRU;
22498c2ecf20Sopenharmony_ci		break;
22508c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_APE_PATCH:
22518c2ecf20Sopenharmony_ci		code_type = CODE_APE_PATCH;
22528c2ecf20Sopenharmony_ci		break;
22538c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_KONG_FW:
22548c2ecf20Sopenharmony_ci		code_type = CODE_KONG_FW;
22558c2ecf20Sopenharmony_ci		break;
22568c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_KONG_PATCH:
22578c2ecf20Sopenharmony_ci		code_type = CODE_KONG_PATCH;
22588c2ecf20Sopenharmony_ci		break;
22598c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BONO_FW:
22608c2ecf20Sopenharmony_ci		code_type = CODE_BONO_FW;
22618c2ecf20Sopenharmony_ci		break;
22628c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BONO_PATCH:
22638c2ecf20Sopenharmony_ci		code_type = CODE_BONO_PATCH;
22648c2ecf20Sopenharmony_ci		break;
22658c2ecf20Sopenharmony_ci	default:
22668c2ecf20Sopenharmony_ci		netdev_err(dev, "Unsupported directory entry type: %u\n",
22678c2ecf20Sopenharmony_ci			   dir_type);
22688c2ecf20Sopenharmony_ci		return -EINVAL;
22698c2ecf20Sopenharmony_ci	}
22708c2ecf20Sopenharmony_ci	if (fw_size < sizeof(struct bnxt_fw_header)) {
22718c2ecf20Sopenharmony_ci		netdev_err(dev, "Invalid firmware file size: %u\n",
22728c2ecf20Sopenharmony_ci			   (unsigned int)fw_size);
22738c2ecf20Sopenharmony_ci		return -EINVAL;
22748c2ecf20Sopenharmony_ci	}
22758c2ecf20Sopenharmony_ci	if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) {
22768c2ecf20Sopenharmony_ci		netdev_err(dev, "Invalid firmware signature: %08X\n",
22778c2ecf20Sopenharmony_ci			   le32_to_cpu(header->signature));
22788c2ecf20Sopenharmony_ci		return -EINVAL;
22798c2ecf20Sopenharmony_ci	}
22808c2ecf20Sopenharmony_ci	if (header->code_type != code_type) {
22818c2ecf20Sopenharmony_ci		netdev_err(dev, "Expected firmware type: %d, read: %d\n",
22828c2ecf20Sopenharmony_ci			   code_type, header->code_type);
22838c2ecf20Sopenharmony_ci		return -EINVAL;
22848c2ecf20Sopenharmony_ci	}
22858c2ecf20Sopenharmony_ci	if (header->device != DEVICE_CUMULUS_FAMILY) {
22868c2ecf20Sopenharmony_ci		netdev_err(dev, "Expected firmware device family %d, read: %d\n",
22878c2ecf20Sopenharmony_ci			   DEVICE_CUMULUS_FAMILY, header->device);
22888c2ecf20Sopenharmony_ci		return -EINVAL;
22898c2ecf20Sopenharmony_ci	}
22908c2ecf20Sopenharmony_ci	/* Confirm the CRC32 checksum of the file: */
22918c2ecf20Sopenharmony_ci	stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
22928c2ecf20Sopenharmony_ci					     sizeof(stored_crc)));
22938c2ecf20Sopenharmony_ci	calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
22948c2ecf20Sopenharmony_ci	if (calculated_crc != stored_crc) {
22958c2ecf20Sopenharmony_ci		netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n",
22968c2ecf20Sopenharmony_ci			   (unsigned long)stored_crc,
22978c2ecf20Sopenharmony_ci			   (unsigned long)calculated_crc);
22988c2ecf20Sopenharmony_ci		return -EINVAL;
22998c2ecf20Sopenharmony_ci	}
23008c2ecf20Sopenharmony_ci	rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
23018c2ecf20Sopenharmony_ci			      0, 0, fw_data, fw_size);
23028c2ecf20Sopenharmony_ci	if (rc == 0)	/* Firmware update successful */
23038c2ecf20Sopenharmony_ci		rc = bnxt_firmware_reset(dev, dir_type);
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	return rc;
23068c2ecf20Sopenharmony_ci}
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_cistatic int bnxt_flash_microcode(struct net_device *dev,
23098c2ecf20Sopenharmony_ci				u16 dir_type,
23108c2ecf20Sopenharmony_ci				const u8 *fw_data,
23118c2ecf20Sopenharmony_ci				size_t fw_size)
23128c2ecf20Sopenharmony_ci{
23138c2ecf20Sopenharmony_ci	struct bnxt_ucode_trailer *trailer;
23148c2ecf20Sopenharmony_ci	u32 calculated_crc;
23158c2ecf20Sopenharmony_ci	u32 stored_crc;
23168c2ecf20Sopenharmony_ci	int rc = 0;
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	if (fw_size < sizeof(struct bnxt_ucode_trailer)) {
23198c2ecf20Sopenharmony_ci		netdev_err(dev, "Invalid microcode file size: %u\n",
23208c2ecf20Sopenharmony_ci			   (unsigned int)fw_size);
23218c2ecf20Sopenharmony_ci		return -EINVAL;
23228c2ecf20Sopenharmony_ci	}
23238c2ecf20Sopenharmony_ci	trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size -
23248c2ecf20Sopenharmony_ci						sizeof(*trailer)));
23258c2ecf20Sopenharmony_ci	if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) {
23268c2ecf20Sopenharmony_ci		netdev_err(dev, "Invalid microcode trailer signature: %08X\n",
23278c2ecf20Sopenharmony_ci			   le32_to_cpu(trailer->sig));
23288c2ecf20Sopenharmony_ci		return -EINVAL;
23298c2ecf20Sopenharmony_ci	}
23308c2ecf20Sopenharmony_ci	if (le16_to_cpu(trailer->dir_type) != dir_type) {
23318c2ecf20Sopenharmony_ci		netdev_err(dev, "Expected microcode type: %d, read: %d\n",
23328c2ecf20Sopenharmony_ci			   dir_type, le16_to_cpu(trailer->dir_type));
23338c2ecf20Sopenharmony_ci		return -EINVAL;
23348c2ecf20Sopenharmony_ci	}
23358c2ecf20Sopenharmony_ci	if (le16_to_cpu(trailer->trailer_length) <
23368c2ecf20Sopenharmony_ci		sizeof(struct bnxt_ucode_trailer)) {
23378c2ecf20Sopenharmony_ci		netdev_err(dev, "Invalid microcode trailer length: %d\n",
23388c2ecf20Sopenharmony_ci			   le16_to_cpu(trailer->trailer_length));
23398c2ecf20Sopenharmony_ci		return -EINVAL;
23408c2ecf20Sopenharmony_ci	}
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	/* Confirm the CRC32 checksum of the file: */
23438c2ecf20Sopenharmony_ci	stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
23448c2ecf20Sopenharmony_ci					     sizeof(stored_crc)));
23458c2ecf20Sopenharmony_ci	calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
23468c2ecf20Sopenharmony_ci	if (calculated_crc != stored_crc) {
23478c2ecf20Sopenharmony_ci		netdev_err(dev,
23488c2ecf20Sopenharmony_ci			   "CRC32 (%08lX) does not match calculated: %08lX\n",
23498c2ecf20Sopenharmony_ci			   (unsigned long)stored_crc,
23508c2ecf20Sopenharmony_ci			   (unsigned long)calculated_crc);
23518c2ecf20Sopenharmony_ci		return -EINVAL;
23528c2ecf20Sopenharmony_ci	}
23538c2ecf20Sopenharmony_ci	rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
23548c2ecf20Sopenharmony_ci			      0, 0, fw_data, fw_size);
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	return rc;
23578c2ecf20Sopenharmony_ci}
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_cistatic bool bnxt_dir_type_is_ape_bin_format(u16 dir_type)
23608c2ecf20Sopenharmony_ci{
23618c2ecf20Sopenharmony_ci	switch (dir_type) {
23628c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_CHIMP_PATCH:
23638c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE:
23648c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BOOTCODE_2:
23658c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_APE_FW:
23668c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_APE_PATCH:
23678c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_KONG_FW:
23688c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_KONG_PATCH:
23698c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BONO_FW:
23708c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_BONO_PATCH:
23718c2ecf20Sopenharmony_ci		return true;
23728c2ecf20Sopenharmony_ci	}
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	return false;
23758c2ecf20Sopenharmony_ci}
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_cistatic bool bnxt_dir_type_is_other_exec_format(u16 dir_type)
23788c2ecf20Sopenharmony_ci{
23798c2ecf20Sopenharmony_ci	switch (dir_type) {
23808c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_AVS:
23818c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_EXP_ROM_MBA:
23828c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_PCIE:
23838c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_TSCF_UCODE:
23848c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_EXT_PHY:
23858c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_CCM:
23868c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_ISCSI_BOOT:
23878c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_ISCSI_BOOT_IPV6:
23888c2ecf20Sopenharmony_ci	case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6:
23898c2ecf20Sopenharmony_ci		return true;
23908c2ecf20Sopenharmony_ci	}
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	return false;
23938c2ecf20Sopenharmony_ci}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_cistatic bool bnxt_dir_type_is_executable(u16 dir_type)
23968c2ecf20Sopenharmony_ci{
23978c2ecf20Sopenharmony_ci	return bnxt_dir_type_is_ape_bin_format(dir_type) ||
23988c2ecf20Sopenharmony_ci		bnxt_dir_type_is_other_exec_format(dir_type);
23998c2ecf20Sopenharmony_ci}
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_cistatic int bnxt_flash_firmware_from_file(struct net_device *dev,
24028c2ecf20Sopenharmony_ci					 u16 dir_type,
24038c2ecf20Sopenharmony_ci					 const char *filename)
24048c2ecf20Sopenharmony_ci{
24058c2ecf20Sopenharmony_ci	const struct firmware  *fw;
24068c2ecf20Sopenharmony_ci	int			rc;
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	rc = request_firmware(&fw, filename, &dev->dev);
24098c2ecf20Sopenharmony_ci	if (rc != 0) {
24108c2ecf20Sopenharmony_ci		netdev_err(dev, "Error %d requesting firmware file: %s\n",
24118c2ecf20Sopenharmony_ci			   rc, filename);
24128c2ecf20Sopenharmony_ci		return rc;
24138c2ecf20Sopenharmony_ci	}
24148c2ecf20Sopenharmony_ci	if (bnxt_dir_type_is_ape_bin_format(dir_type))
24158c2ecf20Sopenharmony_ci		rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size);
24168c2ecf20Sopenharmony_ci	else if (bnxt_dir_type_is_other_exec_format(dir_type))
24178c2ecf20Sopenharmony_ci		rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size);
24188c2ecf20Sopenharmony_ci	else
24198c2ecf20Sopenharmony_ci		rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
24208c2ecf20Sopenharmony_ci				      0, 0, fw->data, fw->size);
24218c2ecf20Sopenharmony_ci	release_firmware(fw);
24228c2ecf20Sopenharmony_ci	return rc;
24238c2ecf20Sopenharmony_ci}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ciint bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
24268c2ecf20Sopenharmony_ci				 u32 install_type)
24278c2ecf20Sopenharmony_ci{
24288c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
24298c2ecf20Sopenharmony_ci	struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr;
24308c2ecf20Sopenharmony_ci	struct hwrm_nvm_install_update_input install = {0};
24318c2ecf20Sopenharmony_ci	const struct firmware *fw;
24328c2ecf20Sopenharmony_ci	u32 item_len;
24338c2ecf20Sopenharmony_ci	int rc = 0;
24348c2ecf20Sopenharmony_ci	u16 index;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	bnxt_hwrm_fw_set_time(bp);
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	rc = bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE,
24398c2ecf20Sopenharmony_ci				  BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
24408c2ecf20Sopenharmony_ci				  &index, &item_len, NULL);
24418c2ecf20Sopenharmony_ci	if (rc) {
24428c2ecf20Sopenharmony_ci		netdev_err(dev, "PKG update area not created in nvram\n");
24438c2ecf20Sopenharmony_ci		return rc;
24448c2ecf20Sopenharmony_ci	}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	rc = request_firmware(&fw, filename, &dev->dev);
24478c2ecf20Sopenharmony_ci	if (rc != 0) {
24488c2ecf20Sopenharmony_ci		netdev_err(dev, "PKG error %d requesting file: %s\n",
24498c2ecf20Sopenharmony_ci			   rc, filename);
24508c2ecf20Sopenharmony_ci		return rc;
24518c2ecf20Sopenharmony_ci	}
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	if (fw->size > item_len) {
24548c2ecf20Sopenharmony_ci		netdev_err(dev, "PKG insufficient update area in nvram: %lu\n",
24558c2ecf20Sopenharmony_ci			   (unsigned long)fw->size);
24568c2ecf20Sopenharmony_ci		rc = -EFBIG;
24578c2ecf20Sopenharmony_ci	} else {
24588c2ecf20Sopenharmony_ci		dma_addr_t dma_handle;
24598c2ecf20Sopenharmony_ci		u8 *kmem;
24608c2ecf20Sopenharmony_ci		struct hwrm_nvm_modify_input modify = {0};
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci		bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1);
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci		modify.dir_idx = cpu_to_le16(index);
24658c2ecf20Sopenharmony_ci		modify.len = cpu_to_le32(fw->size);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci		kmem = dma_alloc_coherent(&bp->pdev->dev, fw->size,
24688c2ecf20Sopenharmony_ci					  &dma_handle, GFP_KERNEL);
24698c2ecf20Sopenharmony_ci		if (!kmem) {
24708c2ecf20Sopenharmony_ci			netdev_err(dev,
24718c2ecf20Sopenharmony_ci				   "dma_alloc_coherent failure, length = %u\n",
24728c2ecf20Sopenharmony_ci				   (unsigned int)fw->size);
24738c2ecf20Sopenharmony_ci			rc = -ENOMEM;
24748c2ecf20Sopenharmony_ci		} else {
24758c2ecf20Sopenharmony_ci			memcpy(kmem, fw->data, fw->size);
24768c2ecf20Sopenharmony_ci			modify.host_src_addr = cpu_to_le64(dma_handle);
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci			rc = hwrm_send_message(bp, &modify, sizeof(modify),
24798c2ecf20Sopenharmony_ci					       FLASH_PACKAGE_TIMEOUT);
24808c2ecf20Sopenharmony_ci			dma_free_coherent(&bp->pdev->dev, fw->size, kmem,
24818c2ecf20Sopenharmony_ci					  dma_handle);
24828c2ecf20Sopenharmony_ci		}
24838c2ecf20Sopenharmony_ci	}
24848c2ecf20Sopenharmony_ci	release_firmware(fw);
24858c2ecf20Sopenharmony_ci	if (rc)
24868c2ecf20Sopenharmony_ci		goto err_exit;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	if ((install_type & 0xffff) == 0)
24898c2ecf20Sopenharmony_ci		install_type >>= 16;
24908c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1);
24918c2ecf20Sopenharmony_ci	install.install_type = cpu_to_le32(install_type);
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
24948c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &install, sizeof(install),
24958c2ecf20Sopenharmony_ci				INSTALL_PACKAGE_TIMEOUT);
24968c2ecf20Sopenharmony_ci	if (rc) {
24978c2ecf20Sopenharmony_ci		u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci		if (resp->error_code && error_code ==
25008c2ecf20Sopenharmony_ci		    NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
25018c2ecf20Sopenharmony_ci			install.flags |= cpu_to_le16(
25028c2ecf20Sopenharmony_ci			       NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
25038c2ecf20Sopenharmony_ci			rc = _hwrm_send_message(bp, &install, sizeof(install),
25048c2ecf20Sopenharmony_ci						INSTALL_PACKAGE_TIMEOUT);
25058c2ecf20Sopenharmony_ci		}
25068c2ecf20Sopenharmony_ci		if (rc)
25078c2ecf20Sopenharmony_ci			goto flash_pkg_exit;
25088c2ecf20Sopenharmony_ci	}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	if (resp->result) {
25118c2ecf20Sopenharmony_ci		netdev_err(dev, "PKG install error = %d, problem_item = %d\n",
25128c2ecf20Sopenharmony_ci			   (s8)resp->result, (int)resp->problem_item);
25138c2ecf20Sopenharmony_ci		rc = -ENOPKG;
25148c2ecf20Sopenharmony_ci	}
25158c2ecf20Sopenharmony_ciflash_pkg_exit:
25168c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
25178c2ecf20Sopenharmony_cierr_exit:
25188c2ecf20Sopenharmony_ci	if (rc == -EACCES)
25198c2ecf20Sopenharmony_ci		bnxt_print_admin_err(bp);
25208c2ecf20Sopenharmony_ci	return rc;
25218c2ecf20Sopenharmony_ci}
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_cistatic int bnxt_flash_device(struct net_device *dev,
25248c2ecf20Sopenharmony_ci			     struct ethtool_flash *flash)
25258c2ecf20Sopenharmony_ci{
25268c2ecf20Sopenharmony_ci	if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) {
25278c2ecf20Sopenharmony_ci		netdev_err(dev, "flashdev not supported from a virtual function\n");
25288c2ecf20Sopenharmony_ci		return -EINVAL;
25298c2ecf20Sopenharmony_ci	}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	if (flash->region == ETHTOOL_FLASH_ALL_REGIONS ||
25328c2ecf20Sopenharmony_ci	    flash->region > 0xffff)
25338c2ecf20Sopenharmony_ci		return bnxt_flash_package_from_file(dev, flash->data,
25348c2ecf20Sopenharmony_ci						    flash->region);
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	return bnxt_flash_firmware_from_file(dev, flash->region, flash->data);
25378c2ecf20Sopenharmony_ci}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_cistatic int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length)
25408c2ecf20Sopenharmony_ci{
25418c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
25428c2ecf20Sopenharmony_ci	int rc;
25438c2ecf20Sopenharmony_ci	struct hwrm_nvm_get_dir_info_input req = {0};
25448c2ecf20Sopenharmony_ci	struct hwrm_nvm_get_dir_info_output *output = bp->hwrm_cmd_resp_addr;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_INFO, -1, -1);
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
25498c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
25508c2ecf20Sopenharmony_ci	if (!rc) {
25518c2ecf20Sopenharmony_ci		*entries = le32_to_cpu(output->entries);
25528c2ecf20Sopenharmony_ci		*length = le32_to_cpu(output->entry_length);
25538c2ecf20Sopenharmony_ci	}
25548c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
25558c2ecf20Sopenharmony_ci	return rc;
25568c2ecf20Sopenharmony_ci}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_cistatic int bnxt_get_eeprom_len(struct net_device *dev)
25598c2ecf20Sopenharmony_ci{
25608c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	if (BNXT_VF(bp))
25638c2ecf20Sopenharmony_ci		return 0;
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	/* The -1 return value allows the entire 32-bit range of offsets to be
25668c2ecf20Sopenharmony_ci	 * passed via the ethtool command-line utility.
25678c2ecf20Sopenharmony_ci	 */
25688c2ecf20Sopenharmony_ci	return -1;
25698c2ecf20Sopenharmony_ci}
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_cistatic int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data)
25728c2ecf20Sopenharmony_ci{
25738c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
25748c2ecf20Sopenharmony_ci	int rc;
25758c2ecf20Sopenharmony_ci	u32 dir_entries;
25768c2ecf20Sopenharmony_ci	u32 entry_length;
25778c2ecf20Sopenharmony_ci	u8 *buf;
25788c2ecf20Sopenharmony_ci	size_t buflen;
25798c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
25808c2ecf20Sopenharmony_ci	struct hwrm_nvm_get_dir_entries_input req = {0};
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	rc = nvm_get_dir_info(dev, &dir_entries, &entry_length);
25838c2ecf20Sopenharmony_ci	if (rc != 0)
25848c2ecf20Sopenharmony_ci		return rc;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	if (!dir_entries || !entry_length)
25878c2ecf20Sopenharmony_ci		return -EIO;
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	/* Insert 2 bytes of directory info (count and size of entries) */
25908c2ecf20Sopenharmony_ci	if (len < 2)
25918c2ecf20Sopenharmony_ci		return -EINVAL;
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci	*data++ = dir_entries;
25948c2ecf20Sopenharmony_ci	*data++ = entry_length;
25958c2ecf20Sopenharmony_ci	len -= 2;
25968c2ecf20Sopenharmony_ci	memset(data, 0xff, len);
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	buflen = dir_entries * entry_length;
25998c2ecf20Sopenharmony_ci	buf = dma_alloc_coherent(&bp->pdev->dev, buflen, &dma_handle,
26008c2ecf20Sopenharmony_ci				 GFP_KERNEL);
26018c2ecf20Sopenharmony_ci	if (!buf) {
26028c2ecf20Sopenharmony_ci		netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
26038c2ecf20Sopenharmony_ci			   (unsigned)buflen);
26048c2ecf20Sopenharmony_ci		return -ENOMEM;
26058c2ecf20Sopenharmony_ci	}
26068c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_ENTRIES, -1, -1);
26078c2ecf20Sopenharmony_ci	req.host_dest_addr = cpu_to_le64(dma_handle);
26088c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
26098c2ecf20Sopenharmony_ci	if (rc == 0)
26108c2ecf20Sopenharmony_ci		memcpy(data, buf, len > buflen ? buflen : len);
26118c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, buflen, buf, dma_handle);
26128c2ecf20Sopenharmony_ci	return rc;
26138c2ecf20Sopenharmony_ci}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_cistatic int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset,
26168c2ecf20Sopenharmony_ci			       u32 length, u8 *data)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
26198c2ecf20Sopenharmony_ci	int rc;
26208c2ecf20Sopenharmony_ci	u8 *buf;
26218c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
26228c2ecf20Sopenharmony_ci	struct hwrm_nvm_read_input req = {0};
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	if (!length)
26258c2ecf20Sopenharmony_ci		return -EINVAL;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	buf = dma_alloc_coherent(&bp->pdev->dev, length, &dma_handle,
26288c2ecf20Sopenharmony_ci				 GFP_KERNEL);
26298c2ecf20Sopenharmony_ci	if (!buf) {
26308c2ecf20Sopenharmony_ci		netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
26318c2ecf20Sopenharmony_ci			   (unsigned)length);
26328c2ecf20Sopenharmony_ci		return -ENOMEM;
26338c2ecf20Sopenharmony_ci	}
26348c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_READ, -1, -1);
26358c2ecf20Sopenharmony_ci	req.host_dest_addr = cpu_to_le64(dma_handle);
26368c2ecf20Sopenharmony_ci	req.dir_idx = cpu_to_le16(index);
26378c2ecf20Sopenharmony_ci	req.offset = cpu_to_le32(offset);
26388c2ecf20Sopenharmony_ci	req.len = cpu_to_le32(length);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
26418c2ecf20Sopenharmony_ci	if (rc == 0)
26428c2ecf20Sopenharmony_ci		memcpy(data, buf, length);
26438c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, length, buf, dma_handle);
26448c2ecf20Sopenharmony_ci	return rc;
26458c2ecf20Sopenharmony_ci}
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_cistatic int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
26488c2ecf20Sopenharmony_ci				u16 ext, u16 *index, u32 *item_length,
26498c2ecf20Sopenharmony_ci				u32 *data_length)
26508c2ecf20Sopenharmony_ci{
26518c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
26528c2ecf20Sopenharmony_ci	int rc;
26538c2ecf20Sopenharmony_ci	struct hwrm_nvm_find_dir_entry_input req = {0};
26548c2ecf20Sopenharmony_ci	struct hwrm_nvm_find_dir_entry_output *output = bp->hwrm_cmd_resp_addr;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_FIND_DIR_ENTRY, -1, -1);
26578c2ecf20Sopenharmony_ci	req.enables = 0;
26588c2ecf20Sopenharmony_ci	req.dir_idx = 0;
26598c2ecf20Sopenharmony_ci	req.dir_type = cpu_to_le16(type);
26608c2ecf20Sopenharmony_ci	req.dir_ordinal = cpu_to_le16(ordinal);
26618c2ecf20Sopenharmony_ci	req.dir_ext = cpu_to_le16(ext);
26628c2ecf20Sopenharmony_ci	req.opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ;
26638c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
26648c2ecf20Sopenharmony_ci	rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
26658c2ecf20Sopenharmony_ci	if (rc == 0) {
26668c2ecf20Sopenharmony_ci		if (index)
26678c2ecf20Sopenharmony_ci			*index = le16_to_cpu(output->dir_idx);
26688c2ecf20Sopenharmony_ci		if (item_length)
26698c2ecf20Sopenharmony_ci			*item_length = le32_to_cpu(output->dir_item_length);
26708c2ecf20Sopenharmony_ci		if (data_length)
26718c2ecf20Sopenharmony_ci			*data_length = le32_to_cpu(output->dir_data_length);
26728c2ecf20Sopenharmony_ci	}
26738c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
26748c2ecf20Sopenharmony_ci	return rc;
26758c2ecf20Sopenharmony_ci}
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_cistatic char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen)
26788c2ecf20Sopenharmony_ci{
26798c2ecf20Sopenharmony_ci	char	*retval = NULL;
26808c2ecf20Sopenharmony_ci	char	*p;
26818c2ecf20Sopenharmony_ci	char	*value;
26828c2ecf20Sopenharmony_ci	int	field = 0;
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci	if (datalen < 1)
26858c2ecf20Sopenharmony_ci		return NULL;
26868c2ecf20Sopenharmony_ci	/* null-terminate the log data (removing last '\n'): */
26878c2ecf20Sopenharmony_ci	data[datalen - 1] = 0;
26888c2ecf20Sopenharmony_ci	for (p = data; *p != 0; p++) {
26898c2ecf20Sopenharmony_ci		field = 0;
26908c2ecf20Sopenharmony_ci		retval = NULL;
26918c2ecf20Sopenharmony_ci		while (*p != 0 && *p != '\n') {
26928c2ecf20Sopenharmony_ci			value = p;
26938c2ecf20Sopenharmony_ci			while (*p != 0 && *p != '\t' && *p != '\n')
26948c2ecf20Sopenharmony_ci				p++;
26958c2ecf20Sopenharmony_ci			if (field == desired_field)
26968c2ecf20Sopenharmony_ci				retval = value;
26978c2ecf20Sopenharmony_ci			if (*p != '\t')
26988c2ecf20Sopenharmony_ci				break;
26998c2ecf20Sopenharmony_ci			*p = 0;
27008c2ecf20Sopenharmony_ci			field++;
27018c2ecf20Sopenharmony_ci			p++;
27028c2ecf20Sopenharmony_ci		}
27038c2ecf20Sopenharmony_ci		if (*p == 0)
27048c2ecf20Sopenharmony_ci			break;
27058c2ecf20Sopenharmony_ci		*p = 0;
27068c2ecf20Sopenharmony_ci	}
27078c2ecf20Sopenharmony_ci	return retval;
27088c2ecf20Sopenharmony_ci}
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_cistatic void bnxt_get_pkgver(struct net_device *dev)
27118c2ecf20Sopenharmony_ci{
27128c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
27138c2ecf20Sopenharmony_ci	u16 index = 0;
27148c2ecf20Sopenharmony_ci	char *pkgver;
27158c2ecf20Sopenharmony_ci	u32 pkglen;
27168c2ecf20Sopenharmony_ci	u8 *pkgbuf;
27178c2ecf20Sopenharmony_ci	int len;
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci	if (bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG,
27208c2ecf20Sopenharmony_ci				 BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
27218c2ecf20Sopenharmony_ci				 &index, NULL, &pkglen) != 0)
27228c2ecf20Sopenharmony_ci		return;
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	pkgbuf = kzalloc(pkglen, GFP_KERNEL);
27258c2ecf20Sopenharmony_ci	if (!pkgbuf) {
27268c2ecf20Sopenharmony_ci		dev_err(&bp->pdev->dev, "Unable to allocate memory for pkg version, length = %u\n",
27278c2ecf20Sopenharmony_ci			pkglen);
27288c2ecf20Sopenharmony_ci		return;
27298c2ecf20Sopenharmony_ci	}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	if (bnxt_get_nvram_item(dev, index, 0, pkglen, pkgbuf))
27328c2ecf20Sopenharmony_ci		goto err;
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	pkgver = bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, pkgbuf,
27358c2ecf20Sopenharmony_ci				   pkglen);
27368c2ecf20Sopenharmony_ci	if (pkgver && *pkgver != 0 && isdigit(*pkgver)) {
27378c2ecf20Sopenharmony_ci		len = strlen(bp->fw_ver_str);
27388c2ecf20Sopenharmony_ci		snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1,
27398c2ecf20Sopenharmony_ci			 "/pkg %s", pkgver);
27408c2ecf20Sopenharmony_ci	}
27418c2ecf20Sopenharmony_cierr:
27428c2ecf20Sopenharmony_ci	kfree(pkgbuf);
27438c2ecf20Sopenharmony_ci}
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_cistatic int bnxt_get_eeprom(struct net_device *dev,
27468c2ecf20Sopenharmony_ci			   struct ethtool_eeprom *eeprom,
27478c2ecf20Sopenharmony_ci			   u8 *data)
27488c2ecf20Sopenharmony_ci{
27498c2ecf20Sopenharmony_ci	u32 index;
27508c2ecf20Sopenharmony_ci	u32 offset;
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	if (eeprom->offset == 0) /* special offset value to get directory */
27538c2ecf20Sopenharmony_ci		return bnxt_get_nvram_directory(dev, eeprom->len, data);
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci	index = eeprom->offset >> 24;
27568c2ecf20Sopenharmony_ci	offset = eeprom->offset & 0xffffff;
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	if (index == 0) {
27598c2ecf20Sopenharmony_ci		netdev_err(dev, "unsupported index value: %d\n", index);
27608c2ecf20Sopenharmony_ci		return -EINVAL;
27618c2ecf20Sopenharmony_ci	}
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci	return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data);
27648c2ecf20Sopenharmony_ci}
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_cistatic int bnxt_erase_nvram_directory(struct net_device *dev, u8 index)
27678c2ecf20Sopenharmony_ci{
27688c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
27698c2ecf20Sopenharmony_ci	struct hwrm_nvm_erase_dir_entry_input req = {0};
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_ERASE_DIR_ENTRY, -1, -1);
27728c2ecf20Sopenharmony_ci	req.dir_idx = cpu_to_le16(index);
27738c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
27748c2ecf20Sopenharmony_ci}
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_cistatic int bnxt_set_eeprom(struct net_device *dev,
27778c2ecf20Sopenharmony_ci			   struct ethtool_eeprom *eeprom,
27788c2ecf20Sopenharmony_ci			   u8 *data)
27798c2ecf20Sopenharmony_ci{
27808c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
27818c2ecf20Sopenharmony_ci	u8 index, dir_op;
27828c2ecf20Sopenharmony_ci	u16 type, ext, ordinal, attr;
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ci	if (!BNXT_PF(bp)) {
27858c2ecf20Sopenharmony_ci		netdev_err(dev, "NVM write not supported from a virtual function\n");
27868c2ecf20Sopenharmony_ci		return -EINVAL;
27878c2ecf20Sopenharmony_ci	}
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	type = eeprom->magic >> 16;
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	if (type == 0xffff) { /* special value for directory operations */
27928c2ecf20Sopenharmony_ci		index = eeprom->magic & 0xff;
27938c2ecf20Sopenharmony_ci		dir_op = eeprom->magic >> 8;
27948c2ecf20Sopenharmony_ci		if (index == 0)
27958c2ecf20Sopenharmony_ci			return -EINVAL;
27968c2ecf20Sopenharmony_ci		switch (dir_op) {
27978c2ecf20Sopenharmony_ci		case 0x0e: /* erase */
27988c2ecf20Sopenharmony_ci			if (eeprom->offset != ~eeprom->magic)
27998c2ecf20Sopenharmony_ci				return -EINVAL;
28008c2ecf20Sopenharmony_ci			return bnxt_erase_nvram_directory(dev, index - 1);
28018c2ecf20Sopenharmony_ci		default:
28028c2ecf20Sopenharmony_ci			return -EINVAL;
28038c2ecf20Sopenharmony_ci		}
28048c2ecf20Sopenharmony_ci	}
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	/* Create or re-write an NVM item: */
28078c2ecf20Sopenharmony_ci	if (bnxt_dir_type_is_executable(type))
28088c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
28098c2ecf20Sopenharmony_ci	ext = eeprom->magic & 0xffff;
28108c2ecf20Sopenharmony_ci	ordinal = eeprom->offset >> 16;
28118c2ecf20Sopenharmony_ci	attr = eeprom->offset & 0xffff;
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	return bnxt_flash_nvram(dev, type, ordinal, ext, attr, data,
28148c2ecf20Sopenharmony_ci				eeprom->len);
28158c2ecf20Sopenharmony_ci}
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_cistatic int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
28188c2ecf20Sopenharmony_ci{
28198c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
28208c2ecf20Sopenharmony_ci	struct ethtool_eee *eee = &bp->eee;
28218c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
28228c2ecf20Sopenharmony_ci	u32 advertising;
28238c2ecf20Sopenharmony_ci	int rc = 0;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
28268c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	if (!(bp->flags & BNXT_FLAG_EEE_CAP))
28298c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
28308c2ecf20Sopenharmony_ci
28318c2ecf20Sopenharmony_ci	mutex_lock(&bp->link_lock);
28328c2ecf20Sopenharmony_ci	advertising = _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
28338c2ecf20Sopenharmony_ci	if (!edata->eee_enabled)
28348c2ecf20Sopenharmony_ci		goto eee_ok;
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
28378c2ecf20Sopenharmony_ci		netdev_warn(dev, "EEE requires autoneg\n");
28388c2ecf20Sopenharmony_ci		rc = -EINVAL;
28398c2ecf20Sopenharmony_ci		goto eee_exit;
28408c2ecf20Sopenharmony_ci	}
28418c2ecf20Sopenharmony_ci	if (edata->tx_lpi_enabled) {
28428c2ecf20Sopenharmony_ci		if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
28438c2ecf20Sopenharmony_ci				       edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
28448c2ecf20Sopenharmony_ci			netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
28458c2ecf20Sopenharmony_ci				    bp->lpi_tmr_lo, bp->lpi_tmr_hi);
28468c2ecf20Sopenharmony_ci			rc = -EINVAL;
28478c2ecf20Sopenharmony_ci			goto eee_exit;
28488c2ecf20Sopenharmony_ci		} else if (!bp->lpi_tmr_hi) {
28498c2ecf20Sopenharmony_ci			edata->tx_lpi_timer = eee->tx_lpi_timer;
28508c2ecf20Sopenharmony_ci		}
28518c2ecf20Sopenharmony_ci	}
28528c2ecf20Sopenharmony_ci	if (!edata->advertised) {
28538c2ecf20Sopenharmony_ci		edata->advertised = advertising & eee->supported;
28548c2ecf20Sopenharmony_ci	} else if (edata->advertised & ~advertising) {
28558c2ecf20Sopenharmony_ci		netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
28568c2ecf20Sopenharmony_ci			    edata->advertised, advertising);
28578c2ecf20Sopenharmony_ci		rc = -EINVAL;
28588c2ecf20Sopenharmony_ci		goto eee_exit;
28598c2ecf20Sopenharmony_ci	}
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ci	eee->advertised = edata->advertised;
28628c2ecf20Sopenharmony_ci	eee->tx_lpi_enabled = edata->tx_lpi_enabled;
28638c2ecf20Sopenharmony_ci	eee->tx_lpi_timer = edata->tx_lpi_timer;
28648c2ecf20Sopenharmony_cieee_ok:
28658c2ecf20Sopenharmony_ci	eee->eee_enabled = edata->eee_enabled;
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci	if (netif_running(dev))
28688c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_set_link_setting(bp, false, true);
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_cieee_exit:
28718c2ecf20Sopenharmony_ci	mutex_unlock(&bp->link_lock);
28728c2ecf20Sopenharmony_ci	return rc;
28738c2ecf20Sopenharmony_ci}
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_cistatic int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata)
28768c2ecf20Sopenharmony_ci{
28778c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci	if (!(bp->flags & BNXT_FLAG_EEE_CAP))
28808c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
28818c2ecf20Sopenharmony_ci
28828c2ecf20Sopenharmony_ci	*edata = bp->eee;
28838c2ecf20Sopenharmony_ci	if (!bp->eee.eee_enabled) {
28848c2ecf20Sopenharmony_ci		/* Preserve tx_lpi_timer so that the last value will be used
28858c2ecf20Sopenharmony_ci		 * by default when it is re-enabled.
28868c2ecf20Sopenharmony_ci		 */
28878c2ecf20Sopenharmony_ci		edata->advertised = 0;
28888c2ecf20Sopenharmony_ci		edata->tx_lpi_enabled = 0;
28898c2ecf20Sopenharmony_ci	}
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci	if (!bp->eee.eee_active)
28928c2ecf20Sopenharmony_ci		edata->lp_advertised = 0;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	return 0;
28958c2ecf20Sopenharmony_ci}
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_cistatic int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr,
28988c2ecf20Sopenharmony_ci					    u16 page_number, u16 start_addr,
28998c2ecf20Sopenharmony_ci					    u16 data_length, u8 *buf)
29008c2ecf20Sopenharmony_ci{
29018c2ecf20Sopenharmony_ci	struct hwrm_port_phy_i2c_read_input req = {0};
29028c2ecf20Sopenharmony_ci	struct hwrm_port_phy_i2c_read_output *output = bp->hwrm_cmd_resp_addr;
29038c2ecf20Sopenharmony_ci	int rc, byte_offset = 0;
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_I2C_READ, -1, -1);
29068c2ecf20Sopenharmony_ci	req.i2c_slave_addr = i2c_addr;
29078c2ecf20Sopenharmony_ci	req.page_number = cpu_to_le16(page_number);
29088c2ecf20Sopenharmony_ci	req.port_id = cpu_to_le16(bp->pf.port_id);
29098c2ecf20Sopenharmony_ci	do {
29108c2ecf20Sopenharmony_ci		u16 xfer_size;
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci		xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE);
29138c2ecf20Sopenharmony_ci		data_length -= xfer_size;
29148c2ecf20Sopenharmony_ci		req.page_offset = cpu_to_le16(start_addr + byte_offset);
29158c2ecf20Sopenharmony_ci		req.data_length = xfer_size;
29168c2ecf20Sopenharmony_ci		req.enables = cpu_to_le32(start_addr + byte_offset ?
29178c2ecf20Sopenharmony_ci				 PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0);
29188c2ecf20Sopenharmony_ci		mutex_lock(&bp->hwrm_cmd_lock);
29198c2ecf20Sopenharmony_ci		rc = _hwrm_send_message(bp, &req, sizeof(req),
29208c2ecf20Sopenharmony_ci					HWRM_CMD_TIMEOUT);
29218c2ecf20Sopenharmony_ci		if (!rc)
29228c2ecf20Sopenharmony_ci			memcpy(buf + byte_offset, output->data, xfer_size);
29238c2ecf20Sopenharmony_ci		mutex_unlock(&bp->hwrm_cmd_lock);
29248c2ecf20Sopenharmony_ci		byte_offset += xfer_size;
29258c2ecf20Sopenharmony_ci	} while (!rc && data_length > 0);
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	return rc;
29288c2ecf20Sopenharmony_ci}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_cistatic int bnxt_get_module_info(struct net_device *dev,
29318c2ecf20Sopenharmony_ci				struct ethtool_modinfo *modinfo)
29328c2ecf20Sopenharmony_ci{
29338c2ecf20Sopenharmony_ci	u8 data[SFF_DIAG_SUPPORT_OFFSET + 1];
29348c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
29358c2ecf20Sopenharmony_ci	int rc;
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci	/* No point in going further if phy status indicates
29388c2ecf20Sopenharmony_ci	 * module is not inserted or if it is powered down or
29398c2ecf20Sopenharmony_ci	 * if it is of type 10GBase-T
29408c2ecf20Sopenharmony_ci	 */
29418c2ecf20Sopenharmony_ci	if (bp->link_info.module_status >
29428c2ecf20Sopenharmony_ci		PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG)
29438c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	/* This feature is not supported in older firmware versions */
29468c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10202)
29478c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci	rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0,
29508c2ecf20Sopenharmony_ci					      SFF_DIAG_SUPPORT_OFFSET + 1,
29518c2ecf20Sopenharmony_ci					      data);
29528c2ecf20Sopenharmony_ci	if (!rc) {
29538c2ecf20Sopenharmony_ci		u8 module_id = data[0];
29548c2ecf20Sopenharmony_ci		u8 diag_supported = data[SFF_DIAG_SUPPORT_OFFSET];
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci		switch (module_id) {
29578c2ecf20Sopenharmony_ci		case SFF_MODULE_ID_SFP:
29588c2ecf20Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8472;
29598c2ecf20Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
29608c2ecf20Sopenharmony_ci			if (!diag_supported)
29618c2ecf20Sopenharmony_ci				modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
29628c2ecf20Sopenharmony_ci			break;
29638c2ecf20Sopenharmony_ci		case SFF_MODULE_ID_QSFP:
29648c2ecf20Sopenharmony_ci		case SFF_MODULE_ID_QSFP_PLUS:
29658c2ecf20Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8436;
29668c2ecf20Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
29678c2ecf20Sopenharmony_ci			break;
29688c2ecf20Sopenharmony_ci		case SFF_MODULE_ID_QSFP28:
29698c2ecf20Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8636;
29708c2ecf20Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
29718c2ecf20Sopenharmony_ci			break;
29728c2ecf20Sopenharmony_ci		default:
29738c2ecf20Sopenharmony_ci			rc = -EOPNOTSUPP;
29748c2ecf20Sopenharmony_ci			break;
29758c2ecf20Sopenharmony_ci		}
29768c2ecf20Sopenharmony_ci	}
29778c2ecf20Sopenharmony_ci	return rc;
29788c2ecf20Sopenharmony_ci}
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_cistatic int bnxt_get_module_eeprom(struct net_device *dev,
29818c2ecf20Sopenharmony_ci				  struct ethtool_eeprom *eeprom,
29828c2ecf20Sopenharmony_ci				  u8 *data)
29838c2ecf20Sopenharmony_ci{
29848c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
29858c2ecf20Sopenharmony_ci	u16  start = eeprom->offset, length = eeprom->len;
29868c2ecf20Sopenharmony_ci	int rc = 0;
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	memset(data, 0, eeprom->len);
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	/* Read A0 portion of the EEPROM */
29918c2ecf20Sopenharmony_ci	if (start < ETH_MODULE_SFF_8436_LEN) {
29928c2ecf20Sopenharmony_ci		if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN)
29938c2ecf20Sopenharmony_ci			length = ETH_MODULE_SFF_8436_LEN - start;
29948c2ecf20Sopenharmony_ci		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0,
29958c2ecf20Sopenharmony_ci						      start, length, data);
29968c2ecf20Sopenharmony_ci		if (rc)
29978c2ecf20Sopenharmony_ci			return rc;
29988c2ecf20Sopenharmony_ci		start += length;
29998c2ecf20Sopenharmony_ci		data += length;
30008c2ecf20Sopenharmony_ci		length = eeprom->len - length;
30018c2ecf20Sopenharmony_ci	}
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	/* Read A2 portion of the EEPROM */
30048c2ecf20Sopenharmony_ci	if (length) {
30058c2ecf20Sopenharmony_ci		start -= ETH_MODULE_SFF_8436_LEN;
30068c2ecf20Sopenharmony_ci		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0,
30078c2ecf20Sopenharmony_ci						      start, length, data);
30088c2ecf20Sopenharmony_ci	}
30098c2ecf20Sopenharmony_ci	return rc;
30108c2ecf20Sopenharmony_ci}
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_cistatic int bnxt_nway_reset(struct net_device *dev)
30138c2ecf20Sopenharmony_ci{
30148c2ecf20Sopenharmony_ci	int rc = 0;
30158c2ecf20Sopenharmony_ci
30168c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
30178c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
30188c2ecf20Sopenharmony_ci
30198c2ecf20Sopenharmony_ci	if (!BNXT_PHY_CFG_ABLE(bp))
30208c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
30238c2ecf20Sopenharmony_ci		return -EINVAL;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (netif_running(dev))
30268c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_set_link_setting(bp, true, false);
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	return rc;
30298c2ecf20Sopenharmony_ci}
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_cistatic int bnxt_set_phys_id(struct net_device *dev,
30328c2ecf20Sopenharmony_ci			    enum ethtool_phys_id_state state)
30338c2ecf20Sopenharmony_ci{
30348c2ecf20Sopenharmony_ci	struct hwrm_port_led_cfg_input req = {0};
30358c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
30368c2ecf20Sopenharmony_ci	struct bnxt_pf_info *pf = &bp->pf;
30378c2ecf20Sopenharmony_ci	struct bnxt_led_cfg *led_cfg;
30388c2ecf20Sopenharmony_ci	u8 led_state;
30398c2ecf20Sopenharmony_ci	__le16 duration;
30408c2ecf20Sopenharmony_ci	int i;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	if (!bp->num_leds || BNXT_VF(bp))
30438c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	if (state == ETHTOOL_ID_ACTIVE) {
30468c2ecf20Sopenharmony_ci		led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT;
30478c2ecf20Sopenharmony_ci		duration = cpu_to_le16(500);
30488c2ecf20Sopenharmony_ci	} else if (state == ETHTOOL_ID_INACTIVE) {
30498c2ecf20Sopenharmony_ci		led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT;
30508c2ecf20Sopenharmony_ci		duration = cpu_to_le16(0);
30518c2ecf20Sopenharmony_ci	} else {
30528c2ecf20Sopenharmony_ci		return -EINVAL;
30538c2ecf20Sopenharmony_ci	}
30548c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_LED_CFG, -1, -1);
30558c2ecf20Sopenharmony_ci	req.port_id = cpu_to_le16(pf->port_id);
30568c2ecf20Sopenharmony_ci	req.num_leds = bp->num_leds;
30578c2ecf20Sopenharmony_ci	led_cfg = (struct bnxt_led_cfg *)&req.led0_id;
30588c2ecf20Sopenharmony_ci	for (i = 0; i < bp->num_leds; i++, led_cfg++) {
30598c2ecf20Sopenharmony_ci		req.enables |= BNXT_LED_DFLT_ENABLES(i);
30608c2ecf20Sopenharmony_ci		led_cfg->led_id = bp->leds[i].led_id;
30618c2ecf20Sopenharmony_ci		led_cfg->led_state = led_state;
30628c2ecf20Sopenharmony_ci		led_cfg->led_blink_on = duration;
30638c2ecf20Sopenharmony_ci		led_cfg->led_blink_off = duration;
30648c2ecf20Sopenharmony_ci		led_cfg->led_group_id = bp->leds[i].led_group_id;
30658c2ecf20Sopenharmony_ci	}
30668c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
30678c2ecf20Sopenharmony_ci}
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_cistatic int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring)
30708c2ecf20Sopenharmony_ci{
30718c2ecf20Sopenharmony_ci	struct hwrm_selftest_irq_input req = {0};
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_IRQ, cmpl_ring, -1);
30748c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
30758c2ecf20Sopenharmony_ci}
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_cistatic int bnxt_test_irq(struct bnxt *bp)
30788c2ecf20Sopenharmony_ci{
30798c2ecf20Sopenharmony_ci	int i;
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	for (i = 0; i < bp->cp_nr_rings; i++) {
30828c2ecf20Sopenharmony_ci		u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id;
30838c2ecf20Sopenharmony_ci		int rc;
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring);
30868c2ecf20Sopenharmony_ci		if (rc)
30878c2ecf20Sopenharmony_ci			return rc;
30888c2ecf20Sopenharmony_ci	}
30898c2ecf20Sopenharmony_ci	return 0;
30908c2ecf20Sopenharmony_ci}
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_cistatic int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable)
30938c2ecf20Sopenharmony_ci{
30948c2ecf20Sopenharmony_ci	struct hwrm_port_mac_cfg_input req = {0};
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ci	req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK);
30998c2ecf20Sopenharmony_ci	if (enable)
31008c2ecf20Sopenharmony_ci		req.lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL;
31018c2ecf20Sopenharmony_ci	else
31028c2ecf20Sopenharmony_ci		req.lpbk = PORT_MAC_CFG_REQ_LPBK_NONE;
31038c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
31048c2ecf20Sopenharmony_ci}
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_cistatic int bnxt_query_force_speeds(struct bnxt *bp, u16 *force_speeds)
31078c2ecf20Sopenharmony_ci{
31088c2ecf20Sopenharmony_ci	struct hwrm_port_phy_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
31098c2ecf20Sopenharmony_ci	struct hwrm_port_phy_qcaps_input req = {0};
31108c2ecf20Sopenharmony_ci	int rc;
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_QCAPS, -1, -1);
31138c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
31148c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
31158c2ecf20Sopenharmony_ci	if (!rc)
31168c2ecf20Sopenharmony_ci		*force_speeds = le16_to_cpu(resp->supported_speeds_force_mode);
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
31198c2ecf20Sopenharmony_ci	return rc;
31208c2ecf20Sopenharmony_ci}
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_cistatic int bnxt_disable_an_for_lpbk(struct bnxt *bp,
31238c2ecf20Sopenharmony_ci				    struct hwrm_port_phy_cfg_input *req)
31248c2ecf20Sopenharmony_ci{
31258c2ecf20Sopenharmony_ci	struct bnxt_link_info *link_info = &bp->link_info;
31268c2ecf20Sopenharmony_ci	u16 fw_advertising;
31278c2ecf20Sopenharmony_ci	u16 fw_speed;
31288c2ecf20Sopenharmony_ci	int rc;
31298c2ecf20Sopenharmony_ci
31308c2ecf20Sopenharmony_ci	if (!link_info->autoneg ||
31318c2ecf20Sopenharmony_ci	    (bp->test_info->flags & BNXT_TEST_FL_AN_PHY_LPBK))
31328c2ecf20Sopenharmony_ci		return 0;
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	rc = bnxt_query_force_speeds(bp, &fw_advertising);
31358c2ecf20Sopenharmony_ci	if (rc)
31368c2ecf20Sopenharmony_ci		return rc;
31378c2ecf20Sopenharmony_ci
31388c2ecf20Sopenharmony_ci	fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
31398c2ecf20Sopenharmony_ci	if (bp->link_info.link_up)
31408c2ecf20Sopenharmony_ci		fw_speed = bp->link_info.link_speed;
31418c2ecf20Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB)
31428c2ecf20Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
31438c2ecf20Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB)
31448c2ecf20Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
31458c2ecf20Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB)
31468c2ecf20Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
31478c2ecf20Sopenharmony_ci	else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB)
31488c2ecf20Sopenharmony_ci		fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci	req->force_link_speed = cpu_to_le16(fw_speed);
31518c2ecf20Sopenharmony_ci	req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE |
31528c2ecf20Sopenharmony_ci				  PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
31538c2ecf20Sopenharmony_ci	rc = hwrm_send_message(bp, req, sizeof(*req), HWRM_CMD_TIMEOUT);
31548c2ecf20Sopenharmony_ci	req->flags = 0;
31558c2ecf20Sopenharmony_ci	req->force_link_speed = cpu_to_le16(0);
31568c2ecf20Sopenharmony_ci	return rc;
31578c2ecf20Sopenharmony_ci}
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_cistatic int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable, bool ext)
31608c2ecf20Sopenharmony_ci{
31618c2ecf20Sopenharmony_ci	struct hwrm_port_phy_cfg_input req = {0};
31628c2ecf20Sopenharmony_ci
31638c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1);
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	if (enable) {
31668c2ecf20Sopenharmony_ci		bnxt_disable_an_for_lpbk(bp, &req);
31678c2ecf20Sopenharmony_ci		if (ext)
31688c2ecf20Sopenharmony_ci			req.lpbk = PORT_PHY_CFG_REQ_LPBK_EXTERNAL;
31698c2ecf20Sopenharmony_ci		else
31708c2ecf20Sopenharmony_ci			req.lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL;
31718c2ecf20Sopenharmony_ci	} else {
31728c2ecf20Sopenharmony_ci		req.lpbk = PORT_PHY_CFG_REQ_LPBK_NONE;
31738c2ecf20Sopenharmony_ci	}
31748c2ecf20Sopenharmony_ci	req.enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK);
31758c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
31768c2ecf20Sopenharmony_ci}
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_cistatic int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
31798c2ecf20Sopenharmony_ci			    u32 raw_cons, int pkt_size)
31808c2ecf20Sopenharmony_ci{
31818c2ecf20Sopenharmony_ci	struct bnxt_napi *bnapi = cpr->bnapi;
31828c2ecf20Sopenharmony_ci	struct bnxt_rx_ring_info *rxr;
31838c2ecf20Sopenharmony_ci	struct bnxt_sw_rx_bd *rx_buf;
31848c2ecf20Sopenharmony_ci	struct rx_cmp *rxcmp;
31858c2ecf20Sopenharmony_ci	u16 cp_cons, cons;
31868c2ecf20Sopenharmony_ci	u8 *data;
31878c2ecf20Sopenharmony_ci	u32 len;
31888c2ecf20Sopenharmony_ci	int i;
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	rxr = bnapi->rx_ring;
31918c2ecf20Sopenharmony_ci	cp_cons = RING_CMP(raw_cons);
31928c2ecf20Sopenharmony_ci	rxcmp = (struct rx_cmp *)
31938c2ecf20Sopenharmony_ci		&cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
31948c2ecf20Sopenharmony_ci	cons = rxcmp->rx_cmp_opaque;
31958c2ecf20Sopenharmony_ci	rx_buf = &rxr->rx_buf_ring[cons];
31968c2ecf20Sopenharmony_ci	data = rx_buf->data_ptr;
31978c2ecf20Sopenharmony_ci	len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT;
31988c2ecf20Sopenharmony_ci	if (len != pkt_size)
31998c2ecf20Sopenharmony_ci		return -EIO;
32008c2ecf20Sopenharmony_ci	i = ETH_ALEN;
32018c2ecf20Sopenharmony_ci	if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr))
32028c2ecf20Sopenharmony_ci		return -EIO;
32038c2ecf20Sopenharmony_ci	i += ETH_ALEN;
32048c2ecf20Sopenharmony_ci	for (  ; i < pkt_size; i++) {
32058c2ecf20Sopenharmony_ci		if (data[i] != (u8)(i & 0xff))
32068c2ecf20Sopenharmony_ci			return -EIO;
32078c2ecf20Sopenharmony_ci	}
32088c2ecf20Sopenharmony_ci	return 0;
32098c2ecf20Sopenharmony_ci}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_cistatic int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
32128c2ecf20Sopenharmony_ci			      int pkt_size)
32138c2ecf20Sopenharmony_ci{
32148c2ecf20Sopenharmony_ci	struct tx_cmp *txcmp;
32158c2ecf20Sopenharmony_ci	int rc = -EIO;
32168c2ecf20Sopenharmony_ci	u32 raw_cons;
32178c2ecf20Sopenharmony_ci	u32 cons;
32188c2ecf20Sopenharmony_ci	int i;
32198c2ecf20Sopenharmony_ci
32208c2ecf20Sopenharmony_ci	raw_cons = cpr->cp_raw_cons;
32218c2ecf20Sopenharmony_ci	for (i = 0; i < 200; i++) {
32228c2ecf20Sopenharmony_ci		cons = RING_CMP(raw_cons);
32238c2ecf20Sopenharmony_ci		txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)];
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ci		if (!TX_CMP_VALID(txcmp, raw_cons)) {
32268c2ecf20Sopenharmony_ci			udelay(5);
32278c2ecf20Sopenharmony_ci			continue;
32288c2ecf20Sopenharmony_ci		}
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci		/* The valid test of the entry must be done first before
32318c2ecf20Sopenharmony_ci		 * reading any further.
32328c2ecf20Sopenharmony_ci		 */
32338c2ecf20Sopenharmony_ci		dma_rmb();
32348c2ecf20Sopenharmony_ci		if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) {
32358c2ecf20Sopenharmony_ci			rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size);
32368c2ecf20Sopenharmony_ci			raw_cons = NEXT_RAW_CMP(raw_cons);
32378c2ecf20Sopenharmony_ci			raw_cons = NEXT_RAW_CMP(raw_cons);
32388c2ecf20Sopenharmony_ci			break;
32398c2ecf20Sopenharmony_ci		}
32408c2ecf20Sopenharmony_ci		raw_cons = NEXT_RAW_CMP(raw_cons);
32418c2ecf20Sopenharmony_ci	}
32428c2ecf20Sopenharmony_ci	cpr->cp_raw_cons = raw_cons;
32438c2ecf20Sopenharmony_ci	return rc;
32448c2ecf20Sopenharmony_ci}
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_cistatic int bnxt_run_loopback(struct bnxt *bp)
32478c2ecf20Sopenharmony_ci{
32488c2ecf20Sopenharmony_ci	struct bnxt_tx_ring_info *txr = &bp->tx_ring[0];
32498c2ecf20Sopenharmony_ci	struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
32508c2ecf20Sopenharmony_ci	struct bnxt_cp_ring_info *cpr;
32518c2ecf20Sopenharmony_ci	int pkt_size, i = 0;
32528c2ecf20Sopenharmony_ci	struct sk_buff *skb;
32538c2ecf20Sopenharmony_ci	dma_addr_t map;
32548c2ecf20Sopenharmony_ci	u8 *data;
32558c2ecf20Sopenharmony_ci	int rc;
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	cpr = &rxr->bnapi->cp_ring;
32588c2ecf20Sopenharmony_ci	if (bp->flags & BNXT_FLAG_CHIP_P5)
32598c2ecf20Sopenharmony_ci		cpr = cpr->cp_ring_arr[BNXT_RX_HDL];
32608c2ecf20Sopenharmony_ci	pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh);
32618c2ecf20Sopenharmony_ci	skb = netdev_alloc_skb(bp->dev, pkt_size);
32628c2ecf20Sopenharmony_ci	if (!skb)
32638c2ecf20Sopenharmony_ci		return -ENOMEM;
32648c2ecf20Sopenharmony_ci	data = skb_put(skb, pkt_size);
32658c2ecf20Sopenharmony_ci	eth_broadcast_addr(data);
32668c2ecf20Sopenharmony_ci	i += ETH_ALEN;
32678c2ecf20Sopenharmony_ci	ether_addr_copy(&data[i], bp->dev->dev_addr);
32688c2ecf20Sopenharmony_ci	i += ETH_ALEN;
32698c2ecf20Sopenharmony_ci	for ( ; i < pkt_size; i++)
32708c2ecf20Sopenharmony_ci		data[i] = (u8)(i & 0xff);
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci	map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
32738c2ecf20Sopenharmony_ci			     PCI_DMA_TODEVICE);
32748c2ecf20Sopenharmony_ci	if (dma_mapping_error(&bp->pdev->dev, map)) {
32758c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
32768c2ecf20Sopenharmony_ci		return -EIO;
32778c2ecf20Sopenharmony_ci	}
32788c2ecf20Sopenharmony_ci	bnxt_xmit_bd(bp, txr, map, pkt_size);
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci	/* Sync BD data before updating doorbell */
32818c2ecf20Sopenharmony_ci	wmb();
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_ci	bnxt_db_write(bp, &txr->tx_db, txr->tx_prod);
32848c2ecf20Sopenharmony_ci	rc = bnxt_poll_loopback(bp, cpr, pkt_size);
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_ci	dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
32878c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
32888c2ecf20Sopenharmony_ci	return rc;
32898c2ecf20Sopenharmony_ci}
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_cistatic int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results)
32928c2ecf20Sopenharmony_ci{
32938c2ecf20Sopenharmony_ci	struct hwrm_selftest_exec_output *resp = bp->hwrm_cmd_resp_addr;
32948c2ecf20Sopenharmony_ci	struct hwrm_selftest_exec_input req = {0};
32958c2ecf20Sopenharmony_ci	int rc;
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_EXEC, -1, -1);
32988c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
32998c2ecf20Sopenharmony_ci	resp->test_success = 0;
33008c2ecf20Sopenharmony_ci	req.flags = test_mask;
33018c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), bp->test_info->timeout);
33028c2ecf20Sopenharmony_ci	*test_results = resp->test_success;
33038c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
33048c2ecf20Sopenharmony_ci	return rc;
33058c2ecf20Sopenharmony_ci}
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci#define BNXT_DRV_TESTS			4
33088c2ecf20Sopenharmony_ci#define BNXT_MACLPBK_TEST_IDX		(bp->num_tests - BNXT_DRV_TESTS)
33098c2ecf20Sopenharmony_ci#define BNXT_PHYLPBK_TEST_IDX		(BNXT_MACLPBK_TEST_IDX + 1)
33108c2ecf20Sopenharmony_ci#define BNXT_EXTLPBK_TEST_IDX		(BNXT_MACLPBK_TEST_IDX + 2)
33118c2ecf20Sopenharmony_ci#define BNXT_IRQ_TEST_IDX		(BNXT_MACLPBK_TEST_IDX + 3)
33128c2ecf20Sopenharmony_ci
33138c2ecf20Sopenharmony_cistatic void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
33148c2ecf20Sopenharmony_ci			   u64 *buf)
33158c2ecf20Sopenharmony_ci{
33168c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
33178c2ecf20Sopenharmony_ci	bool do_ext_lpbk = false;
33188c2ecf20Sopenharmony_ci	bool offline = false;
33198c2ecf20Sopenharmony_ci	u8 test_results = 0;
33208c2ecf20Sopenharmony_ci	u8 test_mask = 0;
33218c2ecf20Sopenharmony_ci	int rc = 0, i;
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci	if (!bp->num_tests || !BNXT_PF(bp))
33248c2ecf20Sopenharmony_ci		return;
33258c2ecf20Sopenharmony_ci	memset(buf, 0, sizeof(u64) * bp->num_tests);
33268c2ecf20Sopenharmony_ci	if (!netif_running(dev)) {
33278c2ecf20Sopenharmony_ci		etest->flags |= ETH_TEST_FL_FAILED;
33288c2ecf20Sopenharmony_ci		return;
33298c2ecf20Sopenharmony_ci	}
33308c2ecf20Sopenharmony_ci
33318c2ecf20Sopenharmony_ci	if ((etest->flags & ETH_TEST_FL_EXTERNAL_LB) &&
33328c2ecf20Sopenharmony_ci	    (bp->test_info->flags & BNXT_TEST_FL_EXT_LPBK))
33338c2ecf20Sopenharmony_ci		do_ext_lpbk = true;
33348c2ecf20Sopenharmony_ci
33358c2ecf20Sopenharmony_ci	if (etest->flags & ETH_TEST_FL_OFFLINE) {
33368c2ecf20Sopenharmony_ci		if (bp->pf.active_vfs || !BNXT_SINGLE_PF(bp)) {
33378c2ecf20Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
33388c2ecf20Sopenharmony_ci			netdev_warn(dev, "Offline tests cannot be run with active VFs or on shared PF\n");
33398c2ecf20Sopenharmony_ci			return;
33408c2ecf20Sopenharmony_ci		}
33418c2ecf20Sopenharmony_ci		offline = true;
33428c2ecf20Sopenharmony_ci	}
33438c2ecf20Sopenharmony_ci
33448c2ecf20Sopenharmony_ci	for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) {
33458c2ecf20Sopenharmony_ci		u8 bit_val = 1 << i;
33468c2ecf20Sopenharmony_ci
33478c2ecf20Sopenharmony_ci		if (!(bp->test_info->offline_mask & bit_val))
33488c2ecf20Sopenharmony_ci			test_mask |= bit_val;
33498c2ecf20Sopenharmony_ci		else if (offline)
33508c2ecf20Sopenharmony_ci			test_mask |= bit_val;
33518c2ecf20Sopenharmony_ci	}
33528c2ecf20Sopenharmony_ci	if (!offline) {
33538c2ecf20Sopenharmony_ci		bnxt_run_fw_tests(bp, test_mask, &test_results);
33548c2ecf20Sopenharmony_ci	} else {
33558c2ecf20Sopenharmony_ci		rc = bnxt_close_nic(bp, false, false);
33568c2ecf20Sopenharmony_ci		if (rc)
33578c2ecf20Sopenharmony_ci			return;
33588c2ecf20Sopenharmony_ci		bnxt_run_fw_tests(bp, test_mask, &test_results);
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci		buf[BNXT_MACLPBK_TEST_IDX] = 1;
33618c2ecf20Sopenharmony_ci		bnxt_hwrm_mac_loopback(bp, true);
33628c2ecf20Sopenharmony_ci		msleep(250);
33638c2ecf20Sopenharmony_ci		rc = bnxt_half_open_nic(bp);
33648c2ecf20Sopenharmony_ci		if (rc) {
33658c2ecf20Sopenharmony_ci			bnxt_hwrm_mac_loopback(bp, false);
33668c2ecf20Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
33678c2ecf20Sopenharmony_ci			return;
33688c2ecf20Sopenharmony_ci		}
33698c2ecf20Sopenharmony_ci		if (bnxt_run_loopback(bp))
33708c2ecf20Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
33718c2ecf20Sopenharmony_ci		else
33728c2ecf20Sopenharmony_ci			buf[BNXT_MACLPBK_TEST_IDX] = 0;
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci		bnxt_hwrm_mac_loopback(bp, false);
33758c2ecf20Sopenharmony_ci		bnxt_hwrm_phy_loopback(bp, true, false);
33768c2ecf20Sopenharmony_ci		msleep(1000);
33778c2ecf20Sopenharmony_ci		if (bnxt_run_loopback(bp)) {
33788c2ecf20Sopenharmony_ci			buf[BNXT_PHYLPBK_TEST_IDX] = 1;
33798c2ecf20Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
33808c2ecf20Sopenharmony_ci		}
33818c2ecf20Sopenharmony_ci		if (do_ext_lpbk) {
33828c2ecf20Sopenharmony_ci			etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
33838c2ecf20Sopenharmony_ci			bnxt_hwrm_phy_loopback(bp, true, true);
33848c2ecf20Sopenharmony_ci			msleep(1000);
33858c2ecf20Sopenharmony_ci			if (bnxt_run_loopback(bp)) {
33868c2ecf20Sopenharmony_ci				buf[BNXT_EXTLPBK_TEST_IDX] = 1;
33878c2ecf20Sopenharmony_ci				etest->flags |= ETH_TEST_FL_FAILED;
33888c2ecf20Sopenharmony_ci			}
33898c2ecf20Sopenharmony_ci		}
33908c2ecf20Sopenharmony_ci		bnxt_hwrm_phy_loopback(bp, false, false);
33918c2ecf20Sopenharmony_ci		bnxt_half_close_nic(bp);
33928c2ecf20Sopenharmony_ci		rc = bnxt_open_nic(bp, false, true);
33938c2ecf20Sopenharmony_ci	}
33948c2ecf20Sopenharmony_ci	if (rc || bnxt_test_irq(bp)) {
33958c2ecf20Sopenharmony_ci		buf[BNXT_IRQ_TEST_IDX] = 1;
33968c2ecf20Sopenharmony_ci		etest->flags |= ETH_TEST_FL_FAILED;
33978c2ecf20Sopenharmony_ci	}
33988c2ecf20Sopenharmony_ci	for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) {
33998c2ecf20Sopenharmony_ci		u8 bit_val = 1 << i;
34008c2ecf20Sopenharmony_ci
34018c2ecf20Sopenharmony_ci		if ((test_mask & bit_val) && !(test_results & bit_val)) {
34028c2ecf20Sopenharmony_ci			buf[i] = 1;
34038c2ecf20Sopenharmony_ci			etest->flags |= ETH_TEST_FL_FAILED;
34048c2ecf20Sopenharmony_ci		}
34058c2ecf20Sopenharmony_ci	}
34068c2ecf20Sopenharmony_ci}
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_cistatic int bnxt_reset(struct net_device *dev, u32 *flags)
34098c2ecf20Sopenharmony_ci{
34108c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
34118c2ecf20Sopenharmony_ci	bool reload = false;
34128c2ecf20Sopenharmony_ci	u32 req = *flags;
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci	if (!req)
34158c2ecf20Sopenharmony_ci		return -EINVAL;
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	if (!BNXT_PF(bp)) {
34188c2ecf20Sopenharmony_ci		netdev_err(dev, "Reset is not supported from a VF\n");
34198c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
34208c2ecf20Sopenharmony_ci	}
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	if (pci_vfs_assigned(bp->pdev) &&
34238c2ecf20Sopenharmony_ci	    !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) {
34248c2ecf20Sopenharmony_ci		netdev_err(dev,
34258c2ecf20Sopenharmony_ci			   "Reset not allowed when VFs are assigned to VMs\n");
34268c2ecf20Sopenharmony_ci		return -EBUSY;
34278c2ecf20Sopenharmony_ci	}
34288c2ecf20Sopenharmony_ci
34298c2ecf20Sopenharmony_ci	if ((req & BNXT_FW_RESET_CHIP) == BNXT_FW_RESET_CHIP) {
34308c2ecf20Sopenharmony_ci		/* This feature is not supported in older firmware versions */
34318c2ecf20Sopenharmony_ci		if (bp->hwrm_spec_code >= 0x10803) {
34328c2ecf20Sopenharmony_ci			if (!bnxt_firmware_reset_chip(dev)) {
34338c2ecf20Sopenharmony_ci				netdev_info(dev, "Firmware reset request successful.\n");
34348c2ecf20Sopenharmony_ci				if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET))
34358c2ecf20Sopenharmony_ci					reload = true;
34368c2ecf20Sopenharmony_ci				*flags &= ~BNXT_FW_RESET_CHIP;
34378c2ecf20Sopenharmony_ci			}
34388c2ecf20Sopenharmony_ci		} else if (req == BNXT_FW_RESET_CHIP) {
34398c2ecf20Sopenharmony_ci			return -EOPNOTSUPP; /* only request, fail hard */
34408c2ecf20Sopenharmony_ci		}
34418c2ecf20Sopenharmony_ci	}
34428c2ecf20Sopenharmony_ci
34438c2ecf20Sopenharmony_ci	if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) {
34448c2ecf20Sopenharmony_ci		/* This feature is not supported in older firmware versions */
34458c2ecf20Sopenharmony_ci		if (bp->hwrm_spec_code >= 0x10803) {
34468c2ecf20Sopenharmony_ci			if (!bnxt_firmware_reset_ap(dev)) {
34478c2ecf20Sopenharmony_ci				netdev_info(dev, "Reset application processor successful.\n");
34488c2ecf20Sopenharmony_ci				reload = true;
34498c2ecf20Sopenharmony_ci				*flags &= ~BNXT_FW_RESET_AP;
34508c2ecf20Sopenharmony_ci			}
34518c2ecf20Sopenharmony_ci		} else if (req == BNXT_FW_RESET_AP) {
34528c2ecf20Sopenharmony_ci			return -EOPNOTSUPP; /* only request, fail hard */
34538c2ecf20Sopenharmony_ci		}
34548c2ecf20Sopenharmony_ci	}
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ci	if (reload)
34578c2ecf20Sopenharmony_ci		netdev_info(dev, "Reload driver to complete reset\n");
34588c2ecf20Sopenharmony_ci
34598c2ecf20Sopenharmony_ci	return 0;
34608c2ecf20Sopenharmony_ci}
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, int msg_len,
34638c2ecf20Sopenharmony_ci				  struct bnxt_hwrm_dbg_dma_info *info)
34648c2ecf20Sopenharmony_ci{
34658c2ecf20Sopenharmony_ci	struct hwrm_dbg_cmn_output *cmn_resp = bp->hwrm_cmd_resp_addr;
34668c2ecf20Sopenharmony_ci	struct hwrm_dbg_cmn_input *cmn_req = msg;
34678c2ecf20Sopenharmony_ci	__le16 *seq_ptr = msg + info->seq_off;
34688c2ecf20Sopenharmony_ci	u16 seq = 0, len, segs_off;
34698c2ecf20Sopenharmony_ci	void *resp = cmn_resp;
34708c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
34718c2ecf20Sopenharmony_ci	int rc, off = 0;
34728c2ecf20Sopenharmony_ci	void *dma_buf;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	dma_buf = dma_alloc_coherent(&bp->pdev->dev, info->dma_len, &dma_handle,
34758c2ecf20Sopenharmony_ci				     GFP_KERNEL);
34768c2ecf20Sopenharmony_ci	if (!dma_buf)
34778c2ecf20Sopenharmony_ci		return -ENOMEM;
34788c2ecf20Sopenharmony_ci
34798c2ecf20Sopenharmony_ci	segs_off = offsetof(struct hwrm_dbg_coredump_list_output,
34808c2ecf20Sopenharmony_ci			    total_segments);
34818c2ecf20Sopenharmony_ci	cmn_req->host_dest_addr = cpu_to_le64(dma_handle);
34828c2ecf20Sopenharmony_ci	cmn_req->host_buf_len = cpu_to_le32(info->dma_len);
34838c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
34848c2ecf20Sopenharmony_ci	while (1) {
34858c2ecf20Sopenharmony_ci		*seq_ptr = cpu_to_le16(seq);
34868c2ecf20Sopenharmony_ci		rc = _hwrm_send_message(bp, msg, msg_len,
34878c2ecf20Sopenharmony_ci					HWRM_COREDUMP_TIMEOUT);
34888c2ecf20Sopenharmony_ci		if (rc)
34898c2ecf20Sopenharmony_ci			break;
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_ci		len = le16_to_cpu(*((__le16 *)(resp + info->data_len_off)));
34928c2ecf20Sopenharmony_ci		if (!seq &&
34938c2ecf20Sopenharmony_ci		    cmn_req->req_type == cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) {
34948c2ecf20Sopenharmony_ci			info->segs = le16_to_cpu(*((__le16 *)(resp +
34958c2ecf20Sopenharmony_ci							      segs_off)));
34968c2ecf20Sopenharmony_ci			if (!info->segs) {
34978c2ecf20Sopenharmony_ci				rc = -EIO;
34988c2ecf20Sopenharmony_ci				break;
34998c2ecf20Sopenharmony_ci			}
35008c2ecf20Sopenharmony_ci
35018c2ecf20Sopenharmony_ci			info->dest_buf_size = info->segs *
35028c2ecf20Sopenharmony_ci					sizeof(struct coredump_segment_record);
35038c2ecf20Sopenharmony_ci			info->dest_buf = kmalloc(info->dest_buf_size,
35048c2ecf20Sopenharmony_ci						 GFP_KERNEL);
35058c2ecf20Sopenharmony_ci			if (!info->dest_buf) {
35068c2ecf20Sopenharmony_ci				rc = -ENOMEM;
35078c2ecf20Sopenharmony_ci				break;
35088c2ecf20Sopenharmony_ci			}
35098c2ecf20Sopenharmony_ci		}
35108c2ecf20Sopenharmony_ci
35118c2ecf20Sopenharmony_ci		if (info->dest_buf) {
35128c2ecf20Sopenharmony_ci			if ((info->seg_start + off + len) <=
35138c2ecf20Sopenharmony_ci			    BNXT_COREDUMP_BUF_LEN(info->buf_len)) {
35148c2ecf20Sopenharmony_ci				memcpy(info->dest_buf + off, dma_buf, len);
35158c2ecf20Sopenharmony_ci			} else {
35168c2ecf20Sopenharmony_ci				rc = -ENOBUFS;
35178c2ecf20Sopenharmony_ci				break;
35188c2ecf20Sopenharmony_ci			}
35198c2ecf20Sopenharmony_ci		}
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci		if (cmn_req->req_type ==
35228c2ecf20Sopenharmony_ci				cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE))
35238c2ecf20Sopenharmony_ci			info->dest_buf_size += len;
35248c2ecf20Sopenharmony_ci
35258c2ecf20Sopenharmony_ci		if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE))
35268c2ecf20Sopenharmony_ci			break;
35278c2ecf20Sopenharmony_ci
35288c2ecf20Sopenharmony_ci		seq++;
35298c2ecf20Sopenharmony_ci		off += len;
35308c2ecf20Sopenharmony_ci	}
35318c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
35328c2ecf20Sopenharmony_ci	dma_free_coherent(&bp->pdev->dev, info->dma_len, dma_buf, dma_handle);
35338c2ecf20Sopenharmony_ci	return rc;
35348c2ecf20Sopenharmony_ci}
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_coredump_list(struct bnxt *bp,
35378c2ecf20Sopenharmony_ci				       struct bnxt_coredump *coredump)
35388c2ecf20Sopenharmony_ci{
35398c2ecf20Sopenharmony_ci	struct hwrm_dbg_coredump_list_input req = {0};
35408c2ecf20Sopenharmony_ci	struct bnxt_hwrm_dbg_dma_info info = {NULL};
35418c2ecf20Sopenharmony_ci	int rc;
35428c2ecf20Sopenharmony_ci
35438c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_COREDUMP_LIST, -1, -1);
35448c2ecf20Sopenharmony_ci
35458c2ecf20Sopenharmony_ci	info.dma_len = COREDUMP_LIST_BUF_LEN;
35468c2ecf20Sopenharmony_ci	info.seq_off = offsetof(struct hwrm_dbg_coredump_list_input, seq_no);
35478c2ecf20Sopenharmony_ci	info.data_len_off = offsetof(struct hwrm_dbg_coredump_list_output,
35488c2ecf20Sopenharmony_ci				     data_len);
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_ci	rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info);
35518c2ecf20Sopenharmony_ci	if (!rc) {
35528c2ecf20Sopenharmony_ci		coredump->data = info.dest_buf;
35538c2ecf20Sopenharmony_ci		coredump->data_size = info.dest_buf_size;
35548c2ecf20Sopenharmony_ci		coredump->total_segs = info.segs;
35558c2ecf20Sopenharmony_ci	}
35568c2ecf20Sopenharmony_ci	return rc;
35578c2ecf20Sopenharmony_ci}
35588c2ecf20Sopenharmony_ci
35598c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id,
35608c2ecf20Sopenharmony_ci					   u16 segment_id)
35618c2ecf20Sopenharmony_ci{
35628c2ecf20Sopenharmony_ci	struct hwrm_dbg_coredump_initiate_input req = {0};
35638c2ecf20Sopenharmony_ci
35648c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_COREDUMP_INITIATE, -1, -1);
35658c2ecf20Sopenharmony_ci	req.component_id = cpu_to_le16(component_id);
35668c2ecf20Sopenharmony_ci	req.segment_id = cpu_to_le16(segment_id);
35678c2ecf20Sopenharmony_ci
35688c2ecf20Sopenharmony_ci	return hwrm_send_message(bp, &req, sizeof(req), HWRM_COREDUMP_TIMEOUT);
35698c2ecf20Sopenharmony_ci}
35708c2ecf20Sopenharmony_ci
35718c2ecf20Sopenharmony_cistatic int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id,
35728c2ecf20Sopenharmony_ci					   u16 segment_id, u32 *seg_len,
35738c2ecf20Sopenharmony_ci					   void *buf, u32 buf_len, u32 offset)
35748c2ecf20Sopenharmony_ci{
35758c2ecf20Sopenharmony_ci	struct hwrm_dbg_coredump_retrieve_input req = {0};
35768c2ecf20Sopenharmony_ci	struct bnxt_hwrm_dbg_dma_info info = {NULL};
35778c2ecf20Sopenharmony_ci	int rc;
35788c2ecf20Sopenharmony_ci
35798c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_DBG_COREDUMP_RETRIEVE, -1, -1);
35808c2ecf20Sopenharmony_ci	req.component_id = cpu_to_le16(component_id);
35818c2ecf20Sopenharmony_ci	req.segment_id = cpu_to_le16(segment_id);
35828c2ecf20Sopenharmony_ci
35838c2ecf20Sopenharmony_ci	info.dma_len = COREDUMP_RETRIEVE_BUF_LEN;
35848c2ecf20Sopenharmony_ci	info.seq_off = offsetof(struct hwrm_dbg_coredump_retrieve_input,
35858c2ecf20Sopenharmony_ci				seq_no);
35868c2ecf20Sopenharmony_ci	info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output,
35878c2ecf20Sopenharmony_ci				     data_len);
35888c2ecf20Sopenharmony_ci	if (buf) {
35898c2ecf20Sopenharmony_ci		info.dest_buf = buf + offset;
35908c2ecf20Sopenharmony_ci		info.buf_len = buf_len;
35918c2ecf20Sopenharmony_ci		info.seg_start = offset;
35928c2ecf20Sopenharmony_ci	}
35938c2ecf20Sopenharmony_ci
35948c2ecf20Sopenharmony_ci	rc = bnxt_hwrm_dbg_dma_data(bp, &req, sizeof(req), &info);
35958c2ecf20Sopenharmony_ci	if (!rc)
35968c2ecf20Sopenharmony_ci		*seg_len = info.dest_buf_size;
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_ci	return rc;
35998c2ecf20Sopenharmony_ci}
36008c2ecf20Sopenharmony_ci
36018c2ecf20Sopenharmony_cistatic void
36028c2ecf20Sopenharmony_cibnxt_fill_coredump_seg_hdr(struct bnxt *bp,
36038c2ecf20Sopenharmony_ci			   struct bnxt_coredump_segment_hdr *seg_hdr,
36048c2ecf20Sopenharmony_ci			   struct coredump_segment_record *seg_rec, u32 seg_len,
36058c2ecf20Sopenharmony_ci			   int status, u32 duration, u32 instance)
36068c2ecf20Sopenharmony_ci{
36078c2ecf20Sopenharmony_ci	memset(seg_hdr, 0, sizeof(*seg_hdr));
36088c2ecf20Sopenharmony_ci	memcpy(seg_hdr->signature, "sEgM", 4);
36098c2ecf20Sopenharmony_ci	if (seg_rec) {
36108c2ecf20Sopenharmony_ci		seg_hdr->component_id = (__force __le32)seg_rec->component_id;
36118c2ecf20Sopenharmony_ci		seg_hdr->segment_id = (__force __le32)seg_rec->segment_id;
36128c2ecf20Sopenharmony_ci		seg_hdr->low_version = seg_rec->version_low;
36138c2ecf20Sopenharmony_ci		seg_hdr->high_version = seg_rec->version_hi;
36148c2ecf20Sopenharmony_ci	} else {
36158c2ecf20Sopenharmony_ci		/* For hwrm_ver_get response Component id = 2
36168c2ecf20Sopenharmony_ci		 * and Segment id = 0
36178c2ecf20Sopenharmony_ci		 */
36188c2ecf20Sopenharmony_ci		seg_hdr->component_id = cpu_to_le32(2);
36198c2ecf20Sopenharmony_ci		seg_hdr->segment_id = 0;
36208c2ecf20Sopenharmony_ci	}
36218c2ecf20Sopenharmony_ci	seg_hdr->function_id = cpu_to_le16(bp->pdev->devfn);
36228c2ecf20Sopenharmony_ci	seg_hdr->length = cpu_to_le32(seg_len);
36238c2ecf20Sopenharmony_ci	seg_hdr->status = cpu_to_le32(status);
36248c2ecf20Sopenharmony_ci	seg_hdr->duration = cpu_to_le32(duration);
36258c2ecf20Sopenharmony_ci	seg_hdr->data_offset = cpu_to_le32(sizeof(*seg_hdr));
36268c2ecf20Sopenharmony_ci	seg_hdr->instance = cpu_to_le32(instance);
36278c2ecf20Sopenharmony_ci}
36288c2ecf20Sopenharmony_ci
36298c2ecf20Sopenharmony_cistatic void
36308c2ecf20Sopenharmony_cibnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record,
36318c2ecf20Sopenharmony_ci			  time64_t start, s16 start_utc, u16 total_segs,
36328c2ecf20Sopenharmony_ci			  int status)
36338c2ecf20Sopenharmony_ci{
36348c2ecf20Sopenharmony_ci	time64_t end = ktime_get_real_seconds();
36358c2ecf20Sopenharmony_ci	u32 os_ver_major = 0, os_ver_minor = 0;
36368c2ecf20Sopenharmony_ci	struct tm tm;
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ci	time64_to_tm(start, 0, &tm);
36398c2ecf20Sopenharmony_ci	memset(record, 0, sizeof(*record));
36408c2ecf20Sopenharmony_ci	memcpy(record->signature, "cOrE", 4);
36418c2ecf20Sopenharmony_ci	record->flags = 0;
36428c2ecf20Sopenharmony_ci	record->low_version = 0;
36438c2ecf20Sopenharmony_ci	record->high_version = 1;
36448c2ecf20Sopenharmony_ci	record->asic_state = 0;
36458c2ecf20Sopenharmony_ci	strlcpy(record->system_name, utsname()->nodename,
36468c2ecf20Sopenharmony_ci		sizeof(record->system_name));
36478c2ecf20Sopenharmony_ci	record->year = cpu_to_le16(tm.tm_year + 1900);
36488c2ecf20Sopenharmony_ci	record->month = cpu_to_le16(tm.tm_mon + 1);
36498c2ecf20Sopenharmony_ci	record->day = cpu_to_le16(tm.tm_mday);
36508c2ecf20Sopenharmony_ci	record->hour = cpu_to_le16(tm.tm_hour);
36518c2ecf20Sopenharmony_ci	record->minute = cpu_to_le16(tm.tm_min);
36528c2ecf20Sopenharmony_ci	record->second = cpu_to_le16(tm.tm_sec);
36538c2ecf20Sopenharmony_ci	record->utc_bias = cpu_to_le16(start_utc);
36548c2ecf20Sopenharmony_ci	strcpy(record->commandline, "ethtool -w");
36558c2ecf20Sopenharmony_ci	record->total_segments = cpu_to_le32(total_segs);
36568c2ecf20Sopenharmony_ci
36578c2ecf20Sopenharmony_ci	sscanf(utsname()->release, "%u.%u", &os_ver_major, &os_ver_minor);
36588c2ecf20Sopenharmony_ci	record->os_ver_major = cpu_to_le32(os_ver_major);
36598c2ecf20Sopenharmony_ci	record->os_ver_minor = cpu_to_le32(os_ver_minor);
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci	strlcpy(record->os_name, utsname()->sysname, 32);
36628c2ecf20Sopenharmony_ci	time64_to_tm(end, 0, &tm);
36638c2ecf20Sopenharmony_ci	record->end_year = cpu_to_le16(tm.tm_year + 1900);
36648c2ecf20Sopenharmony_ci	record->end_month = cpu_to_le16(tm.tm_mon + 1);
36658c2ecf20Sopenharmony_ci	record->end_day = cpu_to_le16(tm.tm_mday);
36668c2ecf20Sopenharmony_ci	record->end_hour = cpu_to_le16(tm.tm_hour);
36678c2ecf20Sopenharmony_ci	record->end_minute = cpu_to_le16(tm.tm_min);
36688c2ecf20Sopenharmony_ci	record->end_second = cpu_to_le16(tm.tm_sec);
36698c2ecf20Sopenharmony_ci	record->end_utc_bias = cpu_to_le16(sys_tz.tz_minuteswest * 60);
36708c2ecf20Sopenharmony_ci	record->asic_id1 = cpu_to_le32(bp->chip_num << 16 |
36718c2ecf20Sopenharmony_ci				       bp->ver_resp.chip_rev << 8 |
36728c2ecf20Sopenharmony_ci				       bp->ver_resp.chip_metal);
36738c2ecf20Sopenharmony_ci	record->asic_id2 = 0;
36748c2ecf20Sopenharmony_ci	record->coredump_status = cpu_to_le32(status);
36758c2ecf20Sopenharmony_ci	record->ioctl_low_version = 0;
36768c2ecf20Sopenharmony_ci	record->ioctl_high_version = 0;
36778c2ecf20Sopenharmony_ci}
36788c2ecf20Sopenharmony_ci
36798c2ecf20Sopenharmony_cistatic int bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len)
36808c2ecf20Sopenharmony_ci{
36818c2ecf20Sopenharmony_ci	u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output);
36828c2ecf20Sopenharmony_ci	u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0;
36838c2ecf20Sopenharmony_ci	struct coredump_segment_record *seg_record = NULL;
36848c2ecf20Sopenharmony_ci	struct bnxt_coredump_segment_hdr seg_hdr;
36858c2ecf20Sopenharmony_ci	struct bnxt_coredump coredump = {NULL};
36868c2ecf20Sopenharmony_ci	time64_t start_time;
36878c2ecf20Sopenharmony_ci	u16 start_utc;
36888c2ecf20Sopenharmony_ci	int rc = 0, i;
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci	if (buf)
36918c2ecf20Sopenharmony_ci		buf_len = *dump_len;
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci	start_time = ktime_get_real_seconds();
36948c2ecf20Sopenharmony_ci	start_utc = sys_tz.tz_minuteswest * 60;
36958c2ecf20Sopenharmony_ci	seg_hdr_len = sizeof(seg_hdr);
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci	/* First segment should be hwrm_ver_get response */
36988c2ecf20Sopenharmony_ci	*dump_len = seg_hdr_len + ver_get_resp_len;
36998c2ecf20Sopenharmony_ci	if (buf) {
37008c2ecf20Sopenharmony_ci		bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, NULL, ver_get_resp_len,
37018c2ecf20Sopenharmony_ci					   0, 0, 0);
37028c2ecf20Sopenharmony_ci		memcpy(buf + offset, &seg_hdr, seg_hdr_len);
37038c2ecf20Sopenharmony_ci		offset += seg_hdr_len;
37048c2ecf20Sopenharmony_ci		memcpy(buf + offset, &bp->ver_resp, ver_get_resp_len);
37058c2ecf20Sopenharmony_ci		offset += ver_get_resp_len;
37068c2ecf20Sopenharmony_ci	}
37078c2ecf20Sopenharmony_ci
37088c2ecf20Sopenharmony_ci	rc = bnxt_hwrm_dbg_coredump_list(bp, &coredump);
37098c2ecf20Sopenharmony_ci	if (rc) {
37108c2ecf20Sopenharmony_ci		netdev_err(bp->dev, "Failed to get coredump segment list\n");
37118c2ecf20Sopenharmony_ci		goto err;
37128c2ecf20Sopenharmony_ci	}
37138c2ecf20Sopenharmony_ci
37148c2ecf20Sopenharmony_ci	*dump_len += seg_hdr_len * coredump.total_segs;
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci	seg_record = (struct coredump_segment_record *)coredump.data;
37178c2ecf20Sopenharmony_ci	seg_record_len = sizeof(*seg_record);
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_ci	for (i = 0; i < coredump.total_segs; i++) {
37208c2ecf20Sopenharmony_ci		u16 comp_id = le16_to_cpu(seg_record->component_id);
37218c2ecf20Sopenharmony_ci		u16 seg_id = le16_to_cpu(seg_record->segment_id);
37228c2ecf20Sopenharmony_ci		u32 duration = 0, seg_len = 0;
37238c2ecf20Sopenharmony_ci		unsigned long start, end;
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci		if (buf && ((offset + seg_hdr_len) >
37268c2ecf20Sopenharmony_ci			    BNXT_COREDUMP_BUF_LEN(buf_len))) {
37278c2ecf20Sopenharmony_ci			rc = -ENOBUFS;
37288c2ecf20Sopenharmony_ci			goto err;
37298c2ecf20Sopenharmony_ci		}
37308c2ecf20Sopenharmony_ci
37318c2ecf20Sopenharmony_ci		start = jiffies;
37328c2ecf20Sopenharmony_ci
37338c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id);
37348c2ecf20Sopenharmony_ci		if (rc) {
37358c2ecf20Sopenharmony_ci			netdev_err(bp->dev,
37368c2ecf20Sopenharmony_ci				   "Failed to initiate coredump for seg = %d\n",
37378c2ecf20Sopenharmony_ci				   seg_record->segment_id);
37388c2ecf20Sopenharmony_ci			goto next_seg;
37398c2ecf20Sopenharmony_ci		}
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci		/* Write segment data into the buffer */
37428c2ecf20Sopenharmony_ci		rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id,
37438c2ecf20Sopenharmony_ci						     &seg_len, buf, buf_len,
37448c2ecf20Sopenharmony_ci						     offset + seg_hdr_len);
37458c2ecf20Sopenharmony_ci		if (rc && rc == -ENOBUFS)
37468c2ecf20Sopenharmony_ci			goto err;
37478c2ecf20Sopenharmony_ci		else if (rc)
37488c2ecf20Sopenharmony_ci			netdev_err(bp->dev,
37498c2ecf20Sopenharmony_ci				   "Failed to retrieve coredump for seg = %d\n",
37508c2ecf20Sopenharmony_ci				   seg_record->segment_id);
37518c2ecf20Sopenharmony_ci
37528c2ecf20Sopenharmony_cinext_seg:
37538c2ecf20Sopenharmony_ci		end = jiffies;
37548c2ecf20Sopenharmony_ci		duration = jiffies_to_msecs(end - start);
37558c2ecf20Sopenharmony_ci		bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, seg_record, seg_len,
37568c2ecf20Sopenharmony_ci					   rc, duration, 0);
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci		if (buf) {
37598c2ecf20Sopenharmony_ci			/* Write segment header into the buffer */
37608c2ecf20Sopenharmony_ci			memcpy(buf + offset, &seg_hdr, seg_hdr_len);
37618c2ecf20Sopenharmony_ci			offset += seg_hdr_len + seg_len;
37628c2ecf20Sopenharmony_ci		}
37638c2ecf20Sopenharmony_ci
37648c2ecf20Sopenharmony_ci		*dump_len += seg_len;
37658c2ecf20Sopenharmony_ci		seg_record =
37668c2ecf20Sopenharmony_ci			(struct coredump_segment_record *)((u8 *)seg_record +
37678c2ecf20Sopenharmony_ci							   seg_record_len);
37688c2ecf20Sopenharmony_ci	}
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_cierr:
37718c2ecf20Sopenharmony_ci	if (buf)
37728c2ecf20Sopenharmony_ci		bnxt_fill_coredump_record(bp, buf + offset, start_time,
37738c2ecf20Sopenharmony_ci					  start_utc, coredump.total_segs + 1,
37748c2ecf20Sopenharmony_ci					  rc);
37758c2ecf20Sopenharmony_ci	kfree(coredump.data);
37768c2ecf20Sopenharmony_ci	*dump_len += sizeof(struct bnxt_coredump_record);
37778c2ecf20Sopenharmony_ci	if (rc == -ENOBUFS)
37788c2ecf20Sopenharmony_ci		netdev_err(bp->dev, "Firmware returned large coredump buffer\n");
37798c2ecf20Sopenharmony_ci	return rc;
37808c2ecf20Sopenharmony_ci}
37818c2ecf20Sopenharmony_ci
37828c2ecf20Sopenharmony_cistatic int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump)
37838c2ecf20Sopenharmony_ci{
37848c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
37858c2ecf20Sopenharmony_ci
37868c2ecf20Sopenharmony_ci	if (dump->flag > BNXT_DUMP_CRASH) {
37878c2ecf20Sopenharmony_ci		netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n");
37888c2ecf20Sopenharmony_ci		return -EINVAL;
37898c2ecf20Sopenharmony_ci	}
37908c2ecf20Sopenharmony_ci
37918c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) {
37928c2ecf20Sopenharmony_ci		netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n");
37938c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
37948c2ecf20Sopenharmony_ci	}
37958c2ecf20Sopenharmony_ci
37968c2ecf20Sopenharmony_ci	bp->dump_flag = dump->flag;
37978c2ecf20Sopenharmony_ci	return 0;
37988c2ecf20Sopenharmony_ci}
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_cistatic int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
38018c2ecf20Sopenharmony_ci{
38028c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10801)
38058c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
38068c2ecf20Sopenharmony_ci
38078c2ecf20Sopenharmony_ci	dump->version = bp->ver_resp.hwrm_fw_maj_8b << 24 |
38088c2ecf20Sopenharmony_ci			bp->ver_resp.hwrm_fw_min_8b << 16 |
38098c2ecf20Sopenharmony_ci			bp->ver_resp.hwrm_fw_bld_8b << 8 |
38108c2ecf20Sopenharmony_ci			bp->ver_resp.hwrm_fw_rsvd_8b;
38118c2ecf20Sopenharmony_ci
38128c2ecf20Sopenharmony_ci	dump->flag = bp->dump_flag;
38138c2ecf20Sopenharmony_ci	if (bp->dump_flag == BNXT_DUMP_CRASH)
38148c2ecf20Sopenharmony_ci		dump->len = BNXT_CRASH_DUMP_LEN;
38158c2ecf20Sopenharmony_ci	else
38168c2ecf20Sopenharmony_ci		bnxt_get_coredump(bp, NULL, &dump->len);
38178c2ecf20Sopenharmony_ci	return 0;
38188c2ecf20Sopenharmony_ci}
38198c2ecf20Sopenharmony_ci
38208c2ecf20Sopenharmony_cistatic int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
38218c2ecf20Sopenharmony_ci			      void *buf)
38228c2ecf20Sopenharmony_ci{
38238c2ecf20Sopenharmony_ci	struct bnxt *bp = netdev_priv(dev);
38248c2ecf20Sopenharmony_ci
38258c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10801)
38268c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
38278c2ecf20Sopenharmony_ci
38288c2ecf20Sopenharmony_ci	memset(buf, 0, dump->len);
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_ci	dump->flag = bp->dump_flag;
38318c2ecf20Sopenharmony_ci	if (dump->flag == BNXT_DUMP_CRASH) {
38328c2ecf20Sopenharmony_ci#ifdef CONFIG_TEE_BNXT_FW
38338c2ecf20Sopenharmony_ci		return tee_bnxt_copy_coredump(buf, 0, dump->len);
38348c2ecf20Sopenharmony_ci#endif
38358c2ecf20Sopenharmony_ci	} else {
38368c2ecf20Sopenharmony_ci		return bnxt_get_coredump(bp, buf, &dump->len);
38378c2ecf20Sopenharmony_ci	}
38388c2ecf20Sopenharmony_ci
38398c2ecf20Sopenharmony_ci	return 0;
38408c2ecf20Sopenharmony_ci}
38418c2ecf20Sopenharmony_ci
38428c2ecf20Sopenharmony_civoid bnxt_ethtool_init(struct bnxt *bp)
38438c2ecf20Sopenharmony_ci{
38448c2ecf20Sopenharmony_ci	struct hwrm_selftest_qlist_output *resp = bp->hwrm_cmd_resp_addr;
38458c2ecf20Sopenharmony_ci	struct hwrm_selftest_qlist_input req = {0};
38468c2ecf20Sopenharmony_ci	struct bnxt_test_info *test_info;
38478c2ecf20Sopenharmony_ci	struct net_device *dev = bp->dev;
38488c2ecf20Sopenharmony_ci	int i, rc;
38498c2ecf20Sopenharmony_ci
38508c2ecf20Sopenharmony_ci	if (!(bp->fw_cap & BNXT_FW_CAP_PKG_VER))
38518c2ecf20Sopenharmony_ci		bnxt_get_pkgver(dev);
38528c2ecf20Sopenharmony_ci
38538c2ecf20Sopenharmony_ci	bp->num_tests = 0;
38548c2ecf20Sopenharmony_ci	if (bp->hwrm_spec_code < 0x10704 || !BNXT_PF(bp))
38558c2ecf20Sopenharmony_ci		return;
38568c2ecf20Sopenharmony_ci
38578c2ecf20Sopenharmony_ci	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_QLIST, -1, -1);
38588c2ecf20Sopenharmony_ci	mutex_lock(&bp->hwrm_cmd_lock);
38598c2ecf20Sopenharmony_ci	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
38608c2ecf20Sopenharmony_ci	if (rc)
38618c2ecf20Sopenharmony_ci		goto ethtool_init_exit;
38628c2ecf20Sopenharmony_ci
38638c2ecf20Sopenharmony_ci	test_info = bp->test_info;
38648c2ecf20Sopenharmony_ci	if (!test_info)
38658c2ecf20Sopenharmony_ci		test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL);
38668c2ecf20Sopenharmony_ci	if (!test_info)
38678c2ecf20Sopenharmony_ci		goto ethtool_init_exit;
38688c2ecf20Sopenharmony_ci
38698c2ecf20Sopenharmony_ci	bp->test_info = test_info;
38708c2ecf20Sopenharmony_ci	bp->num_tests = resp->num_tests + BNXT_DRV_TESTS;
38718c2ecf20Sopenharmony_ci	if (bp->num_tests > BNXT_MAX_TEST)
38728c2ecf20Sopenharmony_ci		bp->num_tests = BNXT_MAX_TEST;
38738c2ecf20Sopenharmony_ci
38748c2ecf20Sopenharmony_ci	test_info->offline_mask = resp->offline_tests;
38758c2ecf20Sopenharmony_ci	test_info->timeout = le16_to_cpu(resp->test_timeout);
38768c2ecf20Sopenharmony_ci	if (!test_info->timeout)
38778c2ecf20Sopenharmony_ci		test_info->timeout = HWRM_CMD_TIMEOUT;
38788c2ecf20Sopenharmony_ci	for (i = 0; i < bp->num_tests; i++) {
38798c2ecf20Sopenharmony_ci		char *str = test_info->string[i];
38808c2ecf20Sopenharmony_ci		char *fw_str = resp->test0_name + i * 32;
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci		if (i == BNXT_MACLPBK_TEST_IDX) {
38838c2ecf20Sopenharmony_ci			strcpy(str, "Mac loopback test (offline)");
38848c2ecf20Sopenharmony_ci		} else if (i == BNXT_PHYLPBK_TEST_IDX) {
38858c2ecf20Sopenharmony_ci			strcpy(str, "Phy loopback test (offline)");
38868c2ecf20Sopenharmony_ci		} else if (i == BNXT_EXTLPBK_TEST_IDX) {
38878c2ecf20Sopenharmony_ci			strcpy(str, "Ext loopback test (offline)");
38888c2ecf20Sopenharmony_ci		} else if (i == BNXT_IRQ_TEST_IDX) {
38898c2ecf20Sopenharmony_ci			strcpy(str, "Interrupt_test (offline)");
38908c2ecf20Sopenharmony_ci		} else {
38918c2ecf20Sopenharmony_ci			strlcpy(str, fw_str, ETH_GSTRING_LEN);
38928c2ecf20Sopenharmony_ci			strncat(str, " test", ETH_GSTRING_LEN - strlen(str));
38938c2ecf20Sopenharmony_ci			if (test_info->offline_mask & (1 << i))
38948c2ecf20Sopenharmony_ci				strncat(str, " (offline)",
38958c2ecf20Sopenharmony_ci					ETH_GSTRING_LEN - strlen(str));
38968c2ecf20Sopenharmony_ci			else
38978c2ecf20Sopenharmony_ci				strncat(str, " (online)",
38988c2ecf20Sopenharmony_ci					ETH_GSTRING_LEN - strlen(str));
38998c2ecf20Sopenharmony_ci		}
39008c2ecf20Sopenharmony_ci	}
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ciethtool_init_exit:
39038c2ecf20Sopenharmony_ci	mutex_unlock(&bp->hwrm_cmd_lock);
39048c2ecf20Sopenharmony_ci}
39058c2ecf20Sopenharmony_ci
39068c2ecf20Sopenharmony_civoid bnxt_ethtool_free(struct bnxt *bp)
39078c2ecf20Sopenharmony_ci{
39088c2ecf20Sopenharmony_ci	kfree(bp->test_info);
39098c2ecf20Sopenharmony_ci	bp->test_info = NULL;
39108c2ecf20Sopenharmony_ci}
39118c2ecf20Sopenharmony_ci
39128c2ecf20Sopenharmony_ciconst struct ethtool_ops bnxt_ethtool_ops = {
39138c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
39148c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES |
39158c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_USECS_IRQ |
39168c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES_IRQ |
39178c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_STATS_BLOCK_USECS |
39188c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
39198c2ecf20Sopenharmony_ci	.get_link_ksettings	= bnxt_get_link_ksettings,
39208c2ecf20Sopenharmony_ci	.set_link_ksettings	= bnxt_set_link_ksettings,
39218c2ecf20Sopenharmony_ci	.get_fecparam		= bnxt_get_fecparam,
39228c2ecf20Sopenharmony_ci	.set_fecparam		= bnxt_set_fecparam,
39238c2ecf20Sopenharmony_ci	.get_pause_stats	= bnxt_get_pause_stats,
39248c2ecf20Sopenharmony_ci	.get_pauseparam		= bnxt_get_pauseparam,
39258c2ecf20Sopenharmony_ci	.set_pauseparam		= bnxt_set_pauseparam,
39268c2ecf20Sopenharmony_ci	.get_drvinfo		= bnxt_get_drvinfo,
39278c2ecf20Sopenharmony_ci	.get_regs_len		= bnxt_get_regs_len,
39288c2ecf20Sopenharmony_ci	.get_regs		= bnxt_get_regs,
39298c2ecf20Sopenharmony_ci	.get_wol		= bnxt_get_wol,
39308c2ecf20Sopenharmony_ci	.set_wol		= bnxt_set_wol,
39318c2ecf20Sopenharmony_ci	.get_coalesce		= bnxt_get_coalesce,
39328c2ecf20Sopenharmony_ci	.set_coalesce		= bnxt_set_coalesce,
39338c2ecf20Sopenharmony_ci	.get_msglevel		= bnxt_get_msglevel,
39348c2ecf20Sopenharmony_ci	.set_msglevel		= bnxt_set_msglevel,
39358c2ecf20Sopenharmony_ci	.get_sset_count		= bnxt_get_sset_count,
39368c2ecf20Sopenharmony_ci	.get_strings		= bnxt_get_strings,
39378c2ecf20Sopenharmony_ci	.get_ethtool_stats	= bnxt_get_ethtool_stats,
39388c2ecf20Sopenharmony_ci	.set_ringparam		= bnxt_set_ringparam,
39398c2ecf20Sopenharmony_ci	.get_ringparam		= bnxt_get_ringparam,
39408c2ecf20Sopenharmony_ci	.get_channels		= bnxt_get_channels,
39418c2ecf20Sopenharmony_ci	.set_channels		= bnxt_set_channels,
39428c2ecf20Sopenharmony_ci	.get_rxnfc		= bnxt_get_rxnfc,
39438c2ecf20Sopenharmony_ci	.set_rxnfc		= bnxt_set_rxnfc,
39448c2ecf20Sopenharmony_ci	.get_rxfh_indir_size    = bnxt_get_rxfh_indir_size,
39458c2ecf20Sopenharmony_ci	.get_rxfh_key_size      = bnxt_get_rxfh_key_size,
39468c2ecf20Sopenharmony_ci	.get_rxfh               = bnxt_get_rxfh,
39478c2ecf20Sopenharmony_ci	.set_rxfh		= bnxt_set_rxfh,
39488c2ecf20Sopenharmony_ci	.flash_device		= bnxt_flash_device,
39498c2ecf20Sopenharmony_ci	.get_eeprom_len         = bnxt_get_eeprom_len,
39508c2ecf20Sopenharmony_ci	.get_eeprom             = bnxt_get_eeprom,
39518c2ecf20Sopenharmony_ci	.set_eeprom		= bnxt_set_eeprom,
39528c2ecf20Sopenharmony_ci	.get_link		= bnxt_get_link,
39538c2ecf20Sopenharmony_ci	.get_eee		= bnxt_get_eee,
39548c2ecf20Sopenharmony_ci	.set_eee		= bnxt_set_eee,
39558c2ecf20Sopenharmony_ci	.get_module_info	= bnxt_get_module_info,
39568c2ecf20Sopenharmony_ci	.get_module_eeprom	= bnxt_get_module_eeprom,
39578c2ecf20Sopenharmony_ci	.nway_reset		= bnxt_nway_reset,
39588c2ecf20Sopenharmony_ci	.set_phys_id		= bnxt_set_phys_id,
39598c2ecf20Sopenharmony_ci	.self_test		= bnxt_self_test,
39608c2ecf20Sopenharmony_ci	.reset			= bnxt_reset,
39618c2ecf20Sopenharmony_ci	.set_dump		= bnxt_set_dump,
39628c2ecf20Sopenharmony_ci	.get_dump_flag		= bnxt_get_dump_flag,
39638c2ecf20Sopenharmony_ci	.get_dump_data		= bnxt_get_dump_data,
39648c2ecf20Sopenharmony_ci};
3965