162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2013-2015 Chelsio Communications.  All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/firmware.h>
762306a36Sopenharmony_ci#include <linux/mdio.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "cxgb4.h"
1062306a36Sopenharmony_ci#include "t4_regs.h"
1162306a36Sopenharmony_ci#include "t4fw_api.h"
1262306a36Sopenharmony_ci#include "cxgb4_cudbg.h"
1362306a36Sopenharmony_ci#include "cxgb4_filter.h"
1462306a36Sopenharmony_ci#include "cxgb4_tc_flower.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define EEPROM_MAGIC 0x38E2F10C
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic u32 get_msglevel(struct net_device *dev)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	return netdev2adap(dev)->msg_enable;
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic void set_msglevel(struct net_device *dev, u32 val)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	netdev2adap(dev)->msg_enable = val;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cienum cxgb4_ethtool_tests {
2962306a36Sopenharmony_ci	CXGB4_ETHTOOL_LB_TEST,
3062306a36Sopenharmony_ci	CXGB4_ETHTOOL_MAX_TEST,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic const char cxgb4_selftest_strings[CXGB4_ETHTOOL_MAX_TEST][ETH_GSTRING_LEN] = {
3462306a36Sopenharmony_ci	"Loop back test (offline)",
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const char * const flash_region_strings[] = {
3862306a36Sopenharmony_ci	"All",
3962306a36Sopenharmony_ci	"Firmware",
4062306a36Sopenharmony_ci	"PHY Firmware",
4162306a36Sopenharmony_ci	"Boot",
4262306a36Sopenharmony_ci	"Boot CFG",
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const char stats_strings[][ETH_GSTRING_LEN] = {
4662306a36Sopenharmony_ci	"tx_octets_ok           ",
4762306a36Sopenharmony_ci	"tx_frames_ok           ",
4862306a36Sopenharmony_ci	"tx_broadcast_frames    ",
4962306a36Sopenharmony_ci	"tx_multicast_frames    ",
5062306a36Sopenharmony_ci	"tx_unicast_frames      ",
5162306a36Sopenharmony_ci	"tx_error_frames        ",
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	"tx_frames_64           ",
5462306a36Sopenharmony_ci	"tx_frames_65_to_127    ",
5562306a36Sopenharmony_ci	"tx_frames_128_to_255   ",
5662306a36Sopenharmony_ci	"tx_frames_256_to_511   ",
5762306a36Sopenharmony_ci	"tx_frames_512_to_1023  ",
5862306a36Sopenharmony_ci	"tx_frames_1024_to_1518 ",
5962306a36Sopenharmony_ci	"tx_frames_1519_to_max  ",
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	"tx_frames_dropped      ",
6262306a36Sopenharmony_ci	"tx_pause_frames        ",
6362306a36Sopenharmony_ci	"tx_ppp0_frames         ",
6462306a36Sopenharmony_ci	"tx_ppp1_frames         ",
6562306a36Sopenharmony_ci	"tx_ppp2_frames         ",
6662306a36Sopenharmony_ci	"tx_ppp3_frames         ",
6762306a36Sopenharmony_ci	"tx_ppp4_frames         ",
6862306a36Sopenharmony_ci	"tx_ppp5_frames         ",
6962306a36Sopenharmony_ci	"tx_ppp6_frames         ",
7062306a36Sopenharmony_ci	"tx_ppp7_frames         ",
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	"rx_octets_ok           ",
7362306a36Sopenharmony_ci	"rx_frames_ok           ",
7462306a36Sopenharmony_ci	"rx_broadcast_frames    ",
7562306a36Sopenharmony_ci	"rx_multicast_frames    ",
7662306a36Sopenharmony_ci	"rx_unicast_frames      ",
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	"rx_frames_too_long     ",
7962306a36Sopenharmony_ci	"rx_jabber_errors       ",
8062306a36Sopenharmony_ci	"rx_fcs_errors          ",
8162306a36Sopenharmony_ci	"rx_length_errors       ",
8262306a36Sopenharmony_ci	"rx_symbol_errors       ",
8362306a36Sopenharmony_ci	"rx_runt_frames         ",
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	"rx_frames_64           ",
8662306a36Sopenharmony_ci	"rx_frames_65_to_127    ",
8762306a36Sopenharmony_ci	"rx_frames_128_to_255   ",
8862306a36Sopenharmony_ci	"rx_frames_256_to_511   ",
8962306a36Sopenharmony_ci	"rx_frames_512_to_1023  ",
9062306a36Sopenharmony_ci	"rx_frames_1024_to_1518 ",
9162306a36Sopenharmony_ci	"rx_frames_1519_to_max  ",
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	"rx_pause_frames        ",
9462306a36Sopenharmony_ci	"rx_ppp0_frames         ",
9562306a36Sopenharmony_ci	"rx_ppp1_frames         ",
9662306a36Sopenharmony_ci	"rx_ppp2_frames         ",
9762306a36Sopenharmony_ci	"rx_ppp3_frames         ",
9862306a36Sopenharmony_ci	"rx_ppp4_frames         ",
9962306a36Sopenharmony_ci	"rx_ppp5_frames         ",
10062306a36Sopenharmony_ci	"rx_ppp6_frames         ",
10162306a36Sopenharmony_ci	"rx_ppp7_frames         ",
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	"rx_bg0_frames_dropped  ",
10462306a36Sopenharmony_ci	"rx_bg1_frames_dropped  ",
10562306a36Sopenharmony_ci	"rx_bg2_frames_dropped  ",
10662306a36Sopenharmony_ci	"rx_bg3_frames_dropped  ",
10762306a36Sopenharmony_ci	"rx_bg0_frames_trunc    ",
10862306a36Sopenharmony_ci	"rx_bg1_frames_trunc    ",
10962306a36Sopenharmony_ci	"rx_bg2_frames_trunc    ",
11062306a36Sopenharmony_ci	"rx_bg3_frames_trunc    ",
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	"tso                    ",
11362306a36Sopenharmony_ci	"uso                    ",
11462306a36Sopenharmony_ci	"tx_csum_offload        ",
11562306a36Sopenharmony_ci	"rx_csum_good           ",
11662306a36Sopenharmony_ci	"vlan_extractions       ",
11762306a36Sopenharmony_ci	"vlan_insertions        ",
11862306a36Sopenharmony_ci	"gro_packets            ",
11962306a36Sopenharmony_ci	"gro_merged             ",
12062306a36Sopenharmony_ci#if  IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
12162306a36Sopenharmony_ci	"tx_tls_encrypted_packets",
12262306a36Sopenharmony_ci	"tx_tls_encrypted_bytes  ",
12362306a36Sopenharmony_ci	"tx_tls_ctx              ",
12462306a36Sopenharmony_ci	"tx_tls_ooo              ",
12562306a36Sopenharmony_ci	"tx_tls_skip_no_sync_data",
12662306a36Sopenharmony_ci	"tx_tls_drop_no_sync_data",
12762306a36Sopenharmony_ci	"tx_tls_drop_bypass_req  ",
12862306a36Sopenharmony_ci#endif
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic char adapter_stats_strings[][ETH_GSTRING_LEN] = {
13262306a36Sopenharmony_ci	"db_drop                ",
13362306a36Sopenharmony_ci	"db_full                ",
13462306a36Sopenharmony_ci	"db_empty               ",
13562306a36Sopenharmony_ci	"write_coal_success     ",
13662306a36Sopenharmony_ci	"write_coal_fail        ",
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic char loopback_stats_strings[][ETH_GSTRING_LEN] = {
14062306a36Sopenharmony_ci	"-------Loopback----------- ",
14162306a36Sopenharmony_ci	"octets_ok              ",
14262306a36Sopenharmony_ci	"frames_ok              ",
14362306a36Sopenharmony_ci	"bcast_frames           ",
14462306a36Sopenharmony_ci	"mcast_frames           ",
14562306a36Sopenharmony_ci	"ucast_frames           ",
14662306a36Sopenharmony_ci	"error_frames           ",
14762306a36Sopenharmony_ci	"frames_64              ",
14862306a36Sopenharmony_ci	"frames_65_to_127       ",
14962306a36Sopenharmony_ci	"frames_128_to_255      ",
15062306a36Sopenharmony_ci	"frames_256_to_511      ",
15162306a36Sopenharmony_ci	"frames_512_to_1023     ",
15262306a36Sopenharmony_ci	"frames_1024_to_1518    ",
15362306a36Sopenharmony_ci	"frames_1519_to_max     ",
15462306a36Sopenharmony_ci	"frames_dropped         ",
15562306a36Sopenharmony_ci	"bg0_frames_dropped     ",
15662306a36Sopenharmony_ci	"bg1_frames_dropped     ",
15762306a36Sopenharmony_ci	"bg2_frames_dropped     ",
15862306a36Sopenharmony_ci	"bg3_frames_dropped     ",
15962306a36Sopenharmony_ci	"bg0_frames_trunc       ",
16062306a36Sopenharmony_ci	"bg1_frames_trunc       ",
16162306a36Sopenharmony_ci	"bg2_frames_trunc       ",
16262306a36Sopenharmony_ci	"bg3_frames_trunc       ",
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic const char cxgb4_priv_flags_strings[][ETH_GSTRING_LEN] = {
16662306a36Sopenharmony_ci	[PRIV_FLAG_PORT_TX_VM_BIT] = "port_tx_vm_wr",
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int get_sset_count(struct net_device *dev, int sset)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	switch (sset) {
17262306a36Sopenharmony_ci	case ETH_SS_STATS:
17362306a36Sopenharmony_ci		return ARRAY_SIZE(stats_strings) +
17462306a36Sopenharmony_ci		       ARRAY_SIZE(adapter_stats_strings) +
17562306a36Sopenharmony_ci		       ARRAY_SIZE(loopback_stats_strings);
17662306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
17762306a36Sopenharmony_ci		return ARRAY_SIZE(cxgb4_priv_flags_strings);
17862306a36Sopenharmony_ci	case ETH_SS_TEST:
17962306a36Sopenharmony_ci		return ARRAY_SIZE(cxgb4_selftest_strings);
18062306a36Sopenharmony_ci	default:
18162306a36Sopenharmony_ci		return -EOPNOTSUPP;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int get_regs_len(struct net_device *dev)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return t4_get_regs_len(adap);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int get_eeprom_len(struct net_device *dev)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return EEPROMSIZE;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
20062306a36Sopenharmony_ci	u32 exprom_vers;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	strscpy(info->driver, cxgb4_driver_name, sizeof(info->driver));
20362306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(adapter->pdev),
20462306a36Sopenharmony_ci		sizeof(info->bus_info));
20562306a36Sopenharmony_ci	info->regdump_len = get_regs_len(dev);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (adapter->params.fw_vers)
20862306a36Sopenharmony_ci		snprintf(info->fw_version, sizeof(info->fw_version),
20962306a36Sopenharmony_ci			 "%u.%u.%u.%u, TP %u.%u.%u.%u",
21062306a36Sopenharmony_ci			 FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers),
21162306a36Sopenharmony_ci			 FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers),
21262306a36Sopenharmony_ci			 FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers),
21362306a36Sopenharmony_ci			 FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers),
21462306a36Sopenharmony_ci			 FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers),
21562306a36Sopenharmony_ci			 FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers),
21662306a36Sopenharmony_ci			 FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers),
21762306a36Sopenharmony_ci			 FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers));
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (!t4_get_exprom_version(adapter, &exprom_vers))
22062306a36Sopenharmony_ci		snprintf(info->erom_version, sizeof(info->erom_version),
22162306a36Sopenharmony_ci			 "%u.%u.%u.%u",
22262306a36Sopenharmony_ci			 FW_HDR_FW_VER_MAJOR_G(exprom_vers),
22362306a36Sopenharmony_ci			 FW_HDR_FW_VER_MINOR_G(exprom_vers),
22462306a36Sopenharmony_ci			 FW_HDR_FW_VER_MICRO_G(exprom_vers),
22562306a36Sopenharmony_ci			 FW_HDR_FW_VER_BUILD_G(exprom_vers));
22662306a36Sopenharmony_ci	info->n_priv_flags = ARRAY_SIZE(cxgb4_priv_flags_strings);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic void get_strings(struct net_device *dev, u32 stringset, u8 *data)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	if (stringset == ETH_SS_STATS) {
23262306a36Sopenharmony_ci		memcpy(data, stats_strings, sizeof(stats_strings));
23362306a36Sopenharmony_ci		data += sizeof(stats_strings);
23462306a36Sopenharmony_ci		memcpy(data, adapter_stats_strings,
23562306a36Sopenharmony_ci		       sizeof(adapter_stats_strings));
23662306a36Sopenharmony_ci		data += sizeof(adapter_stats_strings);
23762306a36Sopenharmony_ci		memcpy(data, loopback_stats_strings,
23862306a36Sopenharmony_ci		       sizeof(loopback_stats_strings));
23962306a36Sopenharmony_ci	} else if (stringset == ETH_SS_PRIV_FLAGS) {
24062306a36Sopenharmony_ci		memcpy(data, cxgb4_priv_flags_strings,
24162306a36Sopenharmony_ci		       sizeof(cxgb4_priv_flags_strings));
24262306a36Sopenharmony_ci	} else if (stringset == ETH_SS_TEST) {
24362306a36Sopenharmony_ci		memcpy(data, cxgb4_selftest_strings,
24462306a36Sopenharmony_ci		       sizeof(cxgb4_selftest_strings));
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/* port stats maintained per queue of the port. They should be in the same
24962306a36Sopenharmony_ci * order as in stats_strings above.
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_cistruct queue_port_stats {
25262306a36Sopenharmony_ci	u64 tso;
25362306a36Sopenharmony_ci	u64 uso;
25462306a36Sopenharmony_ci	u64 tx_csum;
25562306a36Sopenharmony_ci	u64 rx_csum;
25662306a36Sopenharmony_ci	u64 vlan_ex;
25762306a36Sopenharmony_ci	u64 vlan_ins;
25862306a36Sopenharmony_ci	u64 gro_pkts;
25962306a36Sopenharmony_ci	u64 gro_merged;
26062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
26162306a36Sopenharmony_ci	u64 tx_tls_encrypted_packets;
26262306a36Sopenharmony_ci	u64 tx_tls_encrypted_bytes;
26362306a36Sopenharmony_ci	u64 tx_tls_ctx;
26462306a36Sopenharmony_ci	u64 tx_tls_ooo;
26562306a36Sopenharmony_ci	u64 tx_tls_skip_no_sync_data;
26662306a36Sopenharmony_ci	u64 tx_tls_drop_no_sync_data;
26762306a36Sopenharmony_ci	u64 tx_tls_drop_bypass_req;
26862306a36Sopenharmony_ci#endif
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistruct adapter_stats {
27262306a36Sopenharmony_ci	u64 db_drop;
27362306a36Sopenharmony_ci	u64 db_full;
27462306a36Sopenharmony_ci	u64 db_empty;
27562306a36Sopenharmony_ci	u64 wc_success;
27662306a36Sopenharmony_ci	u64 wc_fail;
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void collect_sge_port_stats(const struct adapter *adap,
28062306a36Sopenharmony_ci				   const struct port_info *p,
28162306a36Sopenharmony_ci				   struct queue_port_stats *s)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset];
28462306a36Sopenharmony_ci	const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset];
28562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
28662306a36Sopenharmony_ci	const struct ch_ktls_port_stats_debug *ktls_stats;
28762306a36Sopenharmony_ci#endif
28862306a36Sopenharmony_ci	struct sge_eohw_txq *eohw_tx;
28962306a36Sopenharmony_ci	unsigned int i;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	memset(s, 0, sizeof(*s));
29262306a36Sopenharmony_ci	for (i = 0; i < p->nqsets; i++, rx++, tx++) {
29362306a36Sopenharmony_ci		s->tso += tx->tso;
29462306a36Sopenharmony_ci		s->uso += tx->uso;
29562306a36Sopenharmony_ci		s->tx_csum += tx->tx_cso;
29662306a36Sopenharmony_ci		s->rx_csum += rx->stats.rx_cso;
29762306a36Sopenharmony_ci		s->vlan_ex += rx->stats.vlan_ex;
29862306a36Sopenharmony_ci		s->vlan_ins += tx->vlan_ins;
29962306a36Sopenharmony_ci		s->gro_pkts += rx->stats.lro_pkts;
30062306a36Sopenharmony_ci		s->gro_merged += rx->stats.lro_merged;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (adap->sge.eohw_txq) {
30462306a36Sopenharmony_ci		eohw_tx = &adap->sge.eohw_txq[p->first_qset];
30562306a36Sopenharmony_ci		for (i = 0; i < p->nqsets; i++, eohw_tx++) {
30662306a36Sopenharmony_ci			s->tso += eohw_tx->tso;
30762306a36Sopenharmony_ci			s->uso += eohw_tx->uso;
30862306a36Sopenharmony_ci			s->tx_csum += eohw_tx->tx_cso;
30962306a36Sopenharmony_ci			s->vlan_ins += eohw_tx->vlan_ins;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
31362306a36Sopenharmony_ci	ktls_stats = &adap->ch_ktls_stats.ktls_port[p->port_id];
31462306a36Sopenharmony_ci	s->tx_tls_encrypted_packets =
31562306a36Sopenharmony_ci		atomic64_read(&ktls_stats->ktls_tx_encrypted_packets);
31662306a36Sopenharmony_ci	s->tx_tls_encrypted_bytes =
31762306a36Sopenharmony_ci		atomic64_read(&ktls_stats->ktls_tx_encrypted_bytes);
31862306a36Sopenharmony_ci	s->tx_tls_ctx = atomic64_read(&ktls_stats->ktls_tx_ctx);
31962306a36Sopenharmony_ci	s->tx_tls_ooo = atomic64_read(&ktls_stats->ktls_tx_ooo);
32062306a36Sopenharmony_ci	s->tx_tls_skip_no_sync_data =
32162306a36Sopenharmony_ci		atomic64_read(&ktls_stats->ktls_tx_skip_no_sync_data);
32262306a36Sopenharmony_ci	s->tx_tls_drop_no_sync_data =
32362306a36Sopenharmony_ci		atomic64_read(&ktls_stats->ktls_tx_drop_no_sync_data);
32462306a36Sopenharmony_ci	s->tx_tls_drop_bypass_req =
32562306a36Sopenharmony_ci		atomic64_read(&ktls_stats->ktls_tx_drop_bypass_req);
32662306a36Sopenharmony_ci#endif
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	u64 val1, val2;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	memset(s, 0, sizeof(*s));
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	s->db_drop = adap->db_stats.db_drop;
33662306a36Sopenharmony_ci	s->db_full = adap->db_stats.db_full;
33762306a36Sopenharmony_ci	s->db_empty = adap->db_stats.db_empty;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!is_t4(adap->params.chip)) {
34062306a36Sopenharmony_ci		int v;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		v = t4_read_reg(adap, SGE_STAT_CFG_A);
34362306a36Sopenharmony_ci		if (STATSOURCE_T5_G(v) == 7) {
34462306a36Sopenharmony_ci			val2 = t4_read_reg(adap, SGE_STAT_MATCH_A);
34562306a36Sopenharmony_ci			val1 = t4_read_reg(adap, SGE_STAT_TOTAL_A);
34662306a36Sopenharmony_ci			s->wc_success = val1 - val2;
34762306a36Sopenharmony_ci			s->wc_fail = val2;
34862306a36Sopenharmony_ci		}
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic void get_stats(struct net_device *dev, struct ethtool_stats *stats,
35362306a36Sopenharmony_ci		      u64 *data)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
35662306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
35762306a36Sopenharmony_ci	struct lb_port_stats s;
35862306a36Sopenharmony_ci	int i;
35962306a36Sopenharmony_ci	u64 *p0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	t4_get_port_stats_offset(adapter, pi->tx_chan,
36262306a36Sopenharmony_ci				 (struct port_stats *)data,
36362306a36Sopenharmony_ci				 &pi->stats_base);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	data += sizeof(struct port_stats) / sizeof(u64);
36662306a36Sopenharmony_ci	collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data);
36762306a36Sopenharmony_ci	data += sizeof(struct queue_port_stats) / sizeof(u64);
36862306a36Sopenharmony_ci	collect_adapter_stats(adapter, (struct adapter_stats *)data);
36962306a36Sopenharmony_ci	data += sizeof(struct adapter_stats) / sizeof(u64);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	*data++ = (u64)pi->port_id;
37262306a36Sopenharmony_ci	memset(&s, 0, sizeof(s));
37362306a36Sopenharmony_ci	t4_get_lb_stats(adapter, pi->port_id, &s);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	p0 = &s.octets;
37662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(loopback_stats_strings) - 1; i++)
37762306a36Sopenharmony_ci		*data++ = (unsigned long long)*p0++;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void get_regs(struct net_device *dev, struct ethtool_regs *regs,
38162306a36Sopenharmony_ci		     void *buf)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
38462306a36Sopenharmony_ci	size_t buf_size;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	buf_size = t4_get_regs_len(adap);
38762306a36Sopenharmony_ci	regs->version = mk_adap_vers(adap);
38862306a36Sopenharmony_ci	t4_get_regs(adap, buf, buf_size);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic int restart_autoneg(struct net_device *dev)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (!netif_running(dev))
39662306a36Sopenharmony_ci		return -EAGAIN;
39762306a36Sopenharmony_ci	if (p->link_cfg.autoneg != AUTONEG_ENABLE)
39862306a36Sopenharmony_ci		return -EINVAL;
39962306a36Sopenharmony_ci	t4_restart_aneg(p->adapter, p->adapter->pf, p->tx_chan);
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int identify_port(struct net_device *dev,
40462306a36Sopenharmony_ci			 enum ethtool_phys_id_state state)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	unsigned int val;
40762306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (state == ETHTOOL_ID_ACTIVE)
41062306a36Sopenharmony_ci		val = 0xffff;
41162306a36Sopenharmony_ci	else if (state == ETHTOOL_ID_INACTIVE)
41262306a36Sopenharmony_ci		val = 0;
41362306a36Sopenharmony_ci	else
41462306a36Sopenharmony_ci		return -EINVAL;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return t4_identify_port(adap, adap->pf, netdev2pinfo(dev)->viid, val);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/**
42062306a36Sopenharmony_ci *	from_fw_port_mod_type - translate Firmware Port/Module type to Ethtool
42162306a36Sopenharmony_ci *	@port_type: Firmware Port Type
42262306a36Sopenharmony_ci *	@mod_type: Firmware Module Type
42362306a36Sopenharmony_ci *
42462306a36Sopenharmony_ci *	Translate Firmware Port/Module type to Ethtool Port Type.
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_cistatic int from_fw_port_mod_type(enum fw_port_type port_type,
42762306a36Sopenharmony_ci				 enum fw_port_module_type mod_type)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	if (port_type == FW_PORT_TYPE_BT_SGMII ||
43062306a36Sopenharmony_ci	    port_type == FW_PORT_TYPE_BT_XFI ||
43162306a36Sopenharmony_ci	    port_type == FW_PORT_TYPE_BT_XAUI) {
43262306a36Sopenharmony_ci		return PORT_TP;
43362306a36Sopenharmony_ci	} else if (port_type == FW_PORT_TYPE_FIBER_XFI ||
43462306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_FIBER_XAUI) {
43562306a36Sopenharmony_ci		return PORT_FIBRE;
43662306a36Sopenharmony_ci	} else if (port_type == FW_PORT_TYPE_SFP ||
43762306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_QSFP_10G ||
43862306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_QSA ||
43962306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_QSFP ||
44062306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_CR4_QSFP ||
44162306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_CR_QSFP ||
44262306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_CR2_QSFP ||
44362306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_SFP28) {
44462306a36Sopenharmony_ci		if (mod_type == FW_PORT_MOD_TYPE_LR ||
44562306a36Sopenharmony_ci		    mod_type == FW_PORT_MOD_TYPE_SR ||
44662306a36Sopenharmony_ci		    mod_type == FW_PORT_MOD_TYPE_ER ||
44762306a36Sopenharmony_ci		    mod_type == FW_PORT_MOD_TYPE_LRM)
44862306a36Sopenharmony_ci			return PORT_FIBRE;
44962306a36Sopenharmony_ci		else if (mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE ||
45062306a36Sopenharmony_ci			 mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE)
45162306a36Sopenharmony_ci			return PORT_DA;
45262306a36Sopenharmony_ci		else
45362306a36Sopenharmony_ci			return PORT_OTHER;
45462306a36Sopenharmony_ci	} else if (port_type == FW_PORT_TYPE_KR4_100G ||
45562306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_KR_SFP28 ||
45662306a36Sopenharmony_ci		   port_type == FW_PORT_TYPE_KR_XLAUI) {
45762306a36Sopenharmony_ci		return PORT_NONE;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return PORT_OTHER;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci/**
46462306a36Sopenharmony_ci *	speed_to_fw_caps - translate Port Speed to Firmware Port Capabilities
46562306a36Sopenharmony_ci *	@speed: speed in Kb/s
46662306a36Sopenharmony_ci *
46762306a36Sopenharmony_ci *	Translates a specific Port Speed into a Firmware Port Capabilities
46862306a36Sopenharmony_ci *	value.
46962306a36Sopenharmony_ci */
47062306a36Sopenharmony_cistatic unsigned int speed_to_fw_caps(int speed)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	if (speed == 100)
47362306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_100M;
47462306a36Sopenharmony_ci	if (speed == 1000)
47562306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_1G;
47662306a36Sopenharmony_ci	if (speed == 10000)
47762306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_10G;
47862306a36Sopenharmony_ci	if (speed == 25000)
47962306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_25G;
48062306a36Sopenharmony_ci	if (speed == 40000)
48162306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_40G;
48262306a36Sopenharmony_ci	if (speed == 50000)
48362306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_50G;
48462306a36Sopenharmony_ci	if (speed == 100000)
48562306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_100G;
48662306a36Sopenharmony_ci	if (speed == 200000)
48762306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_200G;
48862306a36Sopenharmony_ci	if (speed == 400000)
48962306a36Sopenharmony_ci		return FW_PORT_CAP32_SPEED_400G;
49062306a36Sopenharmony_ci	return 0;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/**
49462306a36Sopenharmony_ci *	fw_caps_to_lmm - translate Firmware to ethtool Link Mode Mask
49562306a36Sopenharmony_ci *	@port_type: Firmware Port Type
49662306a36Sopenharmony_ci *	@fw_caps: Firmware Port Capabilities
49762306a36Sopenharmony_ci *	@link_mode_mask: ethtool Link Mode Mask
49862306a36Sopenharmony_ci *
49962306a36Sopenharmony_ci *	Translate a Firmware Port Capabilities specification to an ethtool
50062306a36Sopenharmony_ci *	Link Mode Mask.
50162306a36Sopenharmony_ci */
50262306a36Sopenharmony_cistatic void fw_caps_to_lmm(enum fw_port_type port_type,
50362306a36Sopenharmony_ci			   fw_port_cap32_t fw_caps,
50462306a36Sopenharmony_ci			   unsigned long *link_mode_mask)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	#define SET_LMM(__lmm_name) \
50762306a36Sopenharmony_ci		do { \
50862306a36Sopenharmony_ci			__set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \
50962306a36Sopenharmony_ci				  link_mode_mask); \
51062306a36Sopenharmony_ci		} while (0)
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	#define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \
51362306a36Sopenharmony_ci		do { \
51462306a36Sopenharmony_ci			if (fw_caps & FW_PORT_CAP32_ ## __fw_name) \
51562306a36Sopenharmony_ci				SET_LMM(__lmm_name); \
51662306a36Sopenharmony_ci		} while (0)
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	switch (port_type) {
51962306a36Sopenharmony_ci	case FW_PORT_TYPE_BT_SGMII:
52062306a36Sopenharmony_ci	case FW_PORT_TYPE_BT_XFI:
52162306a36Sopenharmony_ci	case FW_PORT_TYPE_BT_XAUI:
52262306a36Sopenharmony_ci		SET_LMM(TP);
52362306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_100M, 100baseT_Full);
52462306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
52562306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full);
52662306a36Sopenharmony_ci		break;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	case FW_PORT_TYPE_KX4:
52962306a36Sopenharmony_ci	case FW_PORT_TYPE_KX:
53062306a36Sopenharmony_ci		SET_LMM(Backplane);
53162306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full);
53262306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKX4_Full);
53362306a36Sopenharmony_ci		break;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	case FW_PORT_TYPE_KR:
53662306a36Sopenharmony_ci		SET_LMM(Backplane);
53762306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
53862306a36Sopenharmony_ci		break;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	case FW_PORT_TYPE_BP_AP:
54162306a36Sopenharmony_ci		SET_LMM(Backplane);
54262306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full);
54362306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseR_FEC);
54462306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
54562306a36Sopenharmony_ci		break;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	case FW_PORT_TYPE_BP4_AP:
54862306a36Sopenharmony_ci		SET_LMM(Backplane);
54962306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full);
55062306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseR_FEC);
55162306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
55262306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKX4_Full);
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	case FW_PORT_TYPE_FIBER_XFI:
55662306a36Sopenharmony_ci	case FW_PORT_TYPE_FIBER_XAUI:
55762306a36Sopenharmony_ci	case FW_PORT_TYPE_SFP:
55862306a36Sopenharmony_ci	case FW_PORT_TYPE_QSFP_10G:
55962306a36Sopenharmony_ci	case FW_PORT_TYPE_QSA:
56062306a36Sopenharmony_ci		SET_LMM(FIBRE);
56162306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
56262306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full);
56362306a36Sopenharmony_ci		break;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	case FW_PORT_TYPE_BP40_BA:
56662306a36Sopenharmony_ci	case FW_PORT_TYPE_QSFP:
56762306a36Sopenharmony_ci		SET_LMM(FIBRE);
56862306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
56962306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full);
57062306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full);
57162306a36Sopenharmony_ci		break;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	case FW_PORT_TYPE_CR_QSFP:
57462306a36Sopenharmony_ci	case FW_PORT_TYPE_SFP28:
57562306a36Sopenharmony_ci		SET_LMM(FIBRE);
57662306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
57762306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full);
57862306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full);
57962306a36Sopenharmony_ci		break;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	case FW_PORT_TYPE_KR_SFP28:
58262306a36Sopenharmony_ci		SET_LMM(Backplane);
58362306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
58462306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
58562306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full);
58662306a36Sopenharmony_ci		break;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	case FW_PORT_TYPE_KR_XLAUI:
58962306a36Sopenharmony_ci		SET_LMM(Backplane);
59062306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full);
59162306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
59262306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_40G, 40000baseKR4_Full);
59362306a36Sopenharmony_ci		break;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	case FW_PORT_TYPE_CR2_QSFP:
59662306a36Sopenharmony_ci		SET_LMM(FIBRE);
59762306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_50G, 50000baseSR2_Full);
59862306a36Sopenharmony_ci		break;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	case FW_PORT_TYPE_KR4_100G:
60162306a36Sopenharmony_ci	case FW_PORT_TYPE_CR4_QSFP:
60262306a36Sopenharmony_ci		SET_LMM(FIBRE);
60362306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_1G,  1000baseT_Full);
60462306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
60562306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full);
60662306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full);
60762306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_50G, 50000baseCR2_Full);
60862306a36Sopenharmony_ci		FW_CAPS_TO_LMM(SPEED_100G, 100000baseCR4_Full);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	default:
61262306a36Sopenharmony_ci		break;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (fw_caps & FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M)) {
61662306a36Sopenharmony_ci		FW_CAPS_TO_LMM(FEC_RS, FEC_RS);
61762306a36Sopenharmony_ci		FW_CAPS_TO_LMM(FEC_BASER_RS, FEC_BASER);
61862306a36Sopenharmony_ci	} else {
61962306a36Sopenharmony_ci		SET_LMM(FEC_NONE);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	FW_CAPS_TO_LMM(ANEG, Autoneg);
62362306a36Sopenharmony_ci	FW_CAPS_TO_LMM(802_3_PAUSE, Pause);
62462306a36Sopenharmony_ci	FW_CAPS_TO_LMM(802_3_ASM_DIR, Asym_Pause);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	#undef FW_CAPS_TO_LMM
62762306a36Sopenharmony_ci	#undef SET_LMM
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci/**
63162306a36Sopenharmony_ci *	lmm_to_fw_caps - translate ethtool Link Mode Mask to Firmware
63262306a36Sopenharmony_ci *	capabilities
63362306a36Sopenharmony_ci *	@link_mode_mask: ethtool Link Mode Mask
63462306a36Sopenharmony_ci *
63562306a36Sopenharmony_ci *	Translate ethtool Link Mode Mask into a Firmware Port capabilities
63662306a36Sopenharmony_ci *	value.
63762306a36Sopenharmony_ci */
63862306a36Sopenharmony_cistatic unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	unsigned int fw_caps = 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	#define LMM_TO_FW_CAPS(__lmm_name, __fw_name) \
64362306a36Sopenharmony_ci		do { \
64462306a36Sopenharmony_ci			if (test_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \
64562306a36Sopenharmony_ci				     link_mode_mask)) \
64662306a36Sopenharmony_ci				fw_caps |= FW_PORT_CAP32_ ## __fw_name; \
64762306a36Sopenharmony_ci		} while (0)
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	LMM_TO_FW_CAPS(100baseT_Full, SPEED_100M);
65062306a36Sopenharmony_ci	LMM_TO_FW_CAPS(1000baseT_Full, SPEED_1G);
65162306a36Sopenharmony_ci	LMM_TO_FW_CAPS(10000baseT_Full, SPEED_10G);
65262306a36Sopenharmony_ci	LMM_TO_FW_CAPS(40000baseSR4_Full, SPEED_40G);
65362306a36Sopenharmony_ci	LMM_TO_FW_CAPS(25000baseCR_Full, SPEED_25G);
65462306a36Sopenharmony_ci	LMM_TO_FW_CAPS(50000baseCR2_Full, SPEED_50G);
65562306a36Sopenharmony_ci	LMM_TO_FW_CAPS(100000baseCR4_Full, SPEED_100G);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	#undef LMM_TO_FW_CAPS
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	return fw_caps;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic int get_link_ksettings(struct net_device *dev,
66362306a36Sopenharmony_ci			      struct ethtool_link_ksettings *link_ksettings)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
66662306a36Sopenharmony_ci	struct ethtool_link_settings *base = &link_ksettings->base;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* For the nonce, the Firmware doesn't send up Port State changes
66962306a36Sopenharmony_ci	 * when the Virtual Interface attached to the Port is down.  So
67062306a36Sopenharmony_ci	 * if it's down, let's grab any changes.
67162306a36Sopenharmony_ci	 */
67262306a36Sopenharmony_ci	if (!netif_running(dev))
67362306a36Sopenharmony_ci		(void)t4_update_port_info(pi);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
67662306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
67762306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (pi->mdio_addr >= 0) {
68262306a36Sopenharmony_ci		base->phy_address = pi->mdio_addr;
68362306a36Sopenharmony_ci		base->mdio_support = (pi->port_type == FW_PORT_TYPE_BT_SGMII
68462306a36Sopenharmony_ci				      ? ETH_MDIO_SUPPORTS_C22
68562306a36Sopenharmony_ci				      : ETH_MDIO_SUPPORTS_C45);
68662306a36Sopenharmony_ci	} else {
68762306a36Sopenharmony_ci		base->phy_address = 255;
68862306a36Sopenharmony_ci		base->mdio_support = 0;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	fw_caps_to_lmm(pi->port_type, pi->link_cfg.pcaps,
69262306a36Sopenharmony_ci		       link_ksettings->link_modes.supported);
69362306a36Sopenharmony_ci	fw_caps_to_lmm(pi->port_type,
69462306a36Sopenharmony_ci		       t4_link_acaps(pi->adapter,
69562306a36Sopenharmony_ci				     pi->lport,
69662306a36Sopenharmony_ci				     &pi->link_cfg),
69762306a36Sopenharmony_ci		       link_ksettings->link_modes.advertising);
69862306a36Sopenharmony_ci	fw_caps_to_lmm(pi->port_type, pi->link_cfg.lpacaps,
69962306a36Sopenharmony_ci		       link_ksettings->link_modes.lp_advertising);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	base->speed = (netif_carrier_ok(dev)
70262306a36Sopenharmony_ci		       ? pi->link_cfg.speed
70362306a36Sopenharmony_ci		       : SPEED_UNKNOWN);
70462306a36Sopenharmony_ci	base->duplex = DUPLEX_FULL;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	base->autoneg = pi->link_cfg.autoneg;
70762306a36Sopenharmony_ci	if (pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG)
70862306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(link_ksettings,
70962306a36Sopenharmony_ci						     supported, Autoneg);
71062306a36Sopenharmony_ci	if (pi->link_cfg.autoneg)
71162306a36Sopenharmony_ci		ethtool_link_ksettings_add_link_mode(link_ksettings,
71262306a36Sopenharmony_ci						     advertising, Autoneg);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return 0;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic int set_link_ksettings(struct net_device *dev,
71862306a36Sopenharmony_ci			    const struct ethtool_link_ksettings *link_ksettings)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
72162306a36Sopenharmony_ci	struct link_config *lc = &pi->link_cfg;
72262306a36Sopenharmony_ci	const struct ethtool_link_settings *base = &link_ksettings->base;
72362306a36Sopenharmony_ci	struct link_config old_lc;
72462306a36Sopenharmony_ci	unsigned int fw_caps;
72562306a36Sopenharmony_ci	int ret = 0;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* only full-duplex supported */
72862306a36Sopenharmony_ci	if (base->duplex != DUPLEX_FULL)
72962306a36Sopenharmony_ci		return -EINVAL;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	old_lc = *lc;
73262306a36Sopenharmony_ci	if (!(lc->pcaps & FW_PORT_CAP32_ANEG) ||
73362306a36Sopenharmony_ci	    base->autoneg == AUTONEG_DISABLE) {
73462306a36Sopenharmony_ci		fw_caps = speed_to_fw_caps(base->speed);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		/* Speed must be supported by Physical Port Capabilities. */
73762306a36Sopenharmony_ci		if (!(lc->pcaps & fw_caps))
73862306a36Sopenharmony_ci			return -EINVAL;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci		lc->speed_caps = fw_caps;
74162306a36Sopenharmony_ci		lc->acaps = fw_caps;
74262306a36Sopenharmony_ci	} else {
74362306a36Sopenharmony_ci		fw_caps =
74462306a36Sopenharmony_ci			lmm_to_fw_caps(link_ksettings->link_modes.advertising);
74562306a36Sopenharmony_ci		if (!(lc->pcaps & fw_caps))
74662306a36Sopenharmony_ci			return -EINVAL;
74762306a36Sopenharmony_ci		lc->speed_caps = 0;
74862306a36Sopenharmony_ci		lc->acaps = fw_caps | FW_PORT_CAP32_ANEG;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci	lc->autoneg = base->autoneg;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	/* If the firmware rejects the Link Configuration request, back out
75362306a36Sopenharmony_ci	 * the changes and report the error.
75462306a36Sopenharmony_ci	 */
75562306a36Sopenharmony_ci	ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox, pi->tx_chan, lc);
75662306a36Sopenharmony_ci	if (ret)
75762306a36Sopenharmony_ci		*lc = old_lc;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	return ret;
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci/* Translate the Firmware FEC value into the ethtool value. */
76362306a36Sopenharmony_cistatic inline unsigned int fwcap_to_eth_fec(unsigned int fw_fec)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	unsigned int eth_fec = 0;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (fw_fec & FW_PORT_CAP32_FEC_RS)
76862306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_RS;
76962306a36Sopenharmony_ci	if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
77062306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_BASER;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* if nothing is set, then FEC is off */
77362306a36Sopenharmony_ci	if (!eth_fec)
77462306a36Sopenharmony_ci		eth_fec = ETHTOOL_FEC_OFF;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	return eth_fec;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci/* Translate Common Code FEC value into ethtool value. */
78062306a36Sopenharmony_cistatic inline unsigned int cc_to_eth_fec(unsigned int cc_fec)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	unsigned int eth_fec = 0;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (cc_fec & FEC_AUTO)
78562306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_AUTO;
78662306a36Sopenharmony_ci	if (cc_fec & FEC_RS)
78762306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_RS;
78862306a36Sopenharmony_ci	if (cc_fec & FEC_BASER_RS)
78962306a36Sopenharmony_ci		eth_fec |= ETHTOOL_FEC_BASER;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/* if nothing is set, then FEC is off */
79262306a36Sopenharmony_ci	if (!eth_fec)
79362306a36Sopenharmony_ci		eth_fec = ETHTOOL_FEC_OFF;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	return eth_fec;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci/* Translate ethtool FEC value into Common Code value. */
79962306a36Sopenharmony_cistatic inline unsigned int eth_to_cc_fec(unsigned int eth_fec)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	unsigned int cc_fec = 0;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_OFF)
80462306a36Sopenharmony_ci		return cc_fec;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_AUTO)
80762306a36Sopenharmony_ci		cc_fec |= FEC_AUTO;
80862306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_RS)
80962306a36Sopenharmony_ci		cc_fec |= FEC_RS;
81062306a36Sopenharmony_ci	if (eth_fec & ETHTOOL_FEC_BASER)
81162306a36Sopenharmony_ci		cc_fec |= FEC_BASER_RS;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	return cc_fec;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic int get_fecparam(struct net_device *dev, struct ethtool_fecparam *fec)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
81962306a36Sopenharmony_ci	const struct link_config *lc = &pi->link_cfg;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	/* Translate the Firmware FEC Support into the ethtool value.  We
82262306a36Sopenharmony_ci	 * always support IEEE 802.3 "automatic" selection of Link FEC type if
82362306a36Sopenharmony_ci	 * any FEC is supported.
82462306a36Sopenharmony_ci	 */
82562306a36Sopenharmony_ci	fec->fec = fwcap_to_eth_fec(lc->pcaps);
82662306a36Sopenharmony_ci	if (fec->fec != ETHTOOL_FEC_OFF)
82762306a36Sopenharmony_ci		fec->fec |= ETHTOOL_FEC_AUTO;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* Translate the current internal FEC parameters into the
83062306a36Sopenharmony_ci	 * ethtool values.
83162306a36Sopenharmony_ci	 */
83262306a36Sopenharmony_ci	fec->active_fec = cc_to_eth_fec(lc->fec);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return 0;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic int set_fecparam(struct net_device *dev, struct ethtool_fecparam *fec)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
84062306a36Sopenharmony_ci	struct link_config *lc = &pi->link_cfg;
84162306a36Sopenharmony_ci	struct link_config old_lc;
84262306a36Sopenharmony_ci	int ret;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	/* Save old Link Configuration in case the L1 Configure below
84562306a36Sopenharmony_ci	 * fails.
84662306a36Sopenharmony_ci	 */
84762306a36Sopenharmony_ci	old_lc = *lc;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* Try to perform the L1 Configure and return the result of that
85062306a36Sopenharmony_ci	 * effort.  If it fails, revert the attempted change.
85162306a36Sopenharmony_ci	 */
85262306a36Sopenharmony_ci	lc->requested_fec = eth_to_cc_fec(fec->fec);
85362306a36Sopenharmony_ci	ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox,
85462306a36Sopenharmony_ci			    pi->tx_chan, lc);
85562306a36Sopenharmony_ci	if (ret)
85662306a36Sopenharmony_ci		*lc = old_lc;
85762306a36Sopenharmony_ci	return ret;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic void get_pauseparam(struct net_device *dev,
86162306a36Sopenharmony_ci			   struct ethtool_pauseparam *epause)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0;
86662306a36Sopenharmony_ci	epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0;
86762306a36Sopenharmony_ci	epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int set_pauseparam(struct net_device *dev,
87162306a36Sopenharmony_ci			  struct ethtool_pauseparam *epause)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct port_info *p = netdev_priv(dev);
87462306a36Sopenharmony_ci	struct link_config *lc = &p->link_cfg;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (epause->autoneg == AUTONEG_DISABLE)
87762306a36Sopenharmony_ci		lc->requested_fc = 0;
87862306a36Sopenharmony_ci	else if (lc->pcaps & FW_PORT_CAP32_ANEG)
87962306a36Sopenharmony_ci		lc->requested_fc = PAUSE_AUTONEG;
88062306a36Sopenharmony_ci	else
88162306a36Sopenharmony_ci		return -EINVAL;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (epause->rx_pause)
88462306a36Sopenharmony_ci		lc->requested_fc |= PAUSE_RX;
88562306a36Sopenharmony_ci	if (epause->tx_pause)
88662306a36Sopenharmony_ci		lc->requested_fc |= PAUSE_TX;
88762306a36Sopenharmony_ci	if (netif_running(dev))
88862306a36Sopenharmony_ci		return t4_link_l1cfg(p->adapter, p->adapter->mbox, p->tx_chan,
88962306a36Sopenharmony_ci				     lc);
89062306a36Sopenharmony_ci	return 0;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e,
89462306a36Sopenharmony_ci			  struct kernel_ethtool_ringparam *kernel_e,
89562306a36Sopenharmony_ci			  struct netlink_ext_ack *extack)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
89862306a36Sopenharmony_ci	const struct sge *s = &pi->adapter->sge;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	e->rx_max_pending = MAX_RX_BUFFERS;
90162306a36Sopenharmony_ci	e->rx_mini_max_pending = MAX_RSPQ_ENTRIES;
90262306a36Sopenharmony_ci	e->rx_jumbo_max_pending = 0;
90362306a36Sopenharmony_ci	e->tx_max_pending = MAX_TXQ_ENTRIES;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8;
90662306a36Sopenharmony_ci	e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size;
90762306a36Sopenharmony_ci	e->rx_jumbo_pending = 0;
90862306a36Sopenharmony_ci	e->tx_pending = s->ethtxq[pi->first_qset].q.size;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e,
91262306a36Sopenharmony_ci			 struct kernel_ethtool_ringparam *kernel_e,
91362306a36Sopenharmony_ci			 struct netlink_ext_ack *extack)
91462306a36Sopenharmony_ci{
91562306a36Sopenharmony_ci	int i;
91662306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
91762306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
91862306a36Sopenharmony_ci	struct sge *s = &adapter->sge;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending ||
92162306a36Sopenharmony_ci	    e->tx_pending > MAX_TXQ_ENTRIES ||
92262306a36Sopenharmony_ci	    e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
92362306a36Sopenharmony_ci	    e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
92462306a36Sopenharmony_ci	    e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES)
92562306a36Sopenharmony_ci		return -EINVAL;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (adapter->flags & CXGB4_FULL_INIT_DONE)
92862306a36Sopenharmony_ci		return -EBUSY;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	for (i = 0; i < pi->nqsets; ++i) {
93162306a36Sopenharmony_ci		s->ethtxq[pi->first_qset + i].q.size = e->tx_pending;
93262306a36Sopenharmony_ci		s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8;
93362306a36Sopenharmony_ci		s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci/**
93962306a36Sopenharmony_ci * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete!
94062306a36Sopenharmony_ci * @dev: the network device
94162306a36Sopenharmony_ci * @us: the hold-off time in us, or 0 to disable timer
94262306a36Sopenharmony_ci * @cnt: the hold-off packet count, or 0 to disable counter
94362306a36Sopenharmony_ci *
94462306a36Sopenharmony_ci * Set the RX interrupt hold-off parameters for a network device.
94562306a36Sopenharmony_ci */
94662306a36Sopenharmony_cistatic int set_rx_intr_params(struct net_device *dev,
94762306a36Sopenharmony_ci			      unsigned int us, unsigned int cnt)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	int i, err;
95062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
95162306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
95262306a36Sopenharmony_ci	struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	for (i = 0; i < pi->nqsets; i++, q++) {
95562306a36Sopenharmony_ci		err = cxgb4_set_rspq_intr_params(&q->rspq, us, cnt);
95662306a36Sopenharmony_ci		if (err)
95762306a36Sopenharmony_ci			return err;
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci	return 0;
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	int i;
96562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
96662306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
96762306a36Sopenharmony_ci	struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	for (i = 0; i < pi->nqsets; i++, q++)
97062306a36Sopenharmony_ci		q->rspq.adaptive_rx = adaptive_rx;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	return 0;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int get_adaptive_rx_setting(struct net_device *dev)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
97862306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
97962306a36Sopenharmony_ci	struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	return q->rspq.adaptive_rx;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci/* Return the current global Adapter SGE Doorbell Queue Timer Tick for all
98562306a36Sopenharmony_ci * Ethernet TX Queues.
98662306a36Sopenharmony_ci */
98762306a36Sopenharmony_cistatic int get_dbqtimer_tick(struct net_device *dev)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
99062306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_SGE_DBQ_TIMER))
99362306a36Sopenharmony_ci		return 0;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return adap->sge.dbqtimer_tick;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci/* Return the SGE Doorbell Queue Timer Value for the Ethernet TX Queues
99962306a36Sopenharmony_ci * associated with a Network Device.
100062306a36Sopenharmony_ci */
100162306a36Sopenharmony_cistatic int get_dbqtimer(struct net_device *dev)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
100462306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
100562306a36Sopenharmony_ci	struct sge_eth_txq *txq;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	txq = &adap->sge.ethtxq[pi->first_qset];
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_SGE_DBQ_TIMER))
101062306a36Sopenharmony_ci		return 0;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/* all of the TX Queues use the same Timer Index */
101362306a36Sopenharmony_ci	return adap->sge.dbqtimer_val[txq->dbqtimerix];
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX
101762306a36Sopenharmony_ci * Queues.  This is the fundamental "Tick" that sets the scale of values which
101862306a36Sopenharmony_ci * can be used.  Individual Ethernet TX Queues index into a relatively small
101962306a36Sopenharmony_ci * array of Tick Multipliers.  Changing the base Tick will thus change all of
102062306a36Sopenharmony_ci * the resulting Timer Values associated with those multipliers for all
102162306a36Sopenharmony_ci * Ethernet TX Queues.
102262306a36Sopenharmony_ci */
102362306a36Sopenharmony_cistatic int set_dbqtimer_tick(struct net_device *dev, int usecs)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
102662306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
102762306a36Sopenharmony_ci	struct sge *s = &adap->sge;
102862306a36Sopenharmony_ci	u32 param, val;
102962306a36Sopenharmony_ci	int ret;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_SGE_DBQ_TIMER))
103262306a36Sopenharmony_ci		return 0;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/* return early if it's the same Timer Tick we're already using */
103562306a36Sopenharmony_ci	if (s->dbqtimer_tick == usecs)
103662306a36Sopenharmony_ci		return 0;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	/* attempt to set the new Timer Tick value */
103962306a36Sopenharmony_ci	param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
104062306a36Sopenharmony_ci		 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK));
104162306a36Sopenharmony_ci	val = usecs;
104262306a36Sopenharmony_ci	ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, &param, &val);
104362306a36Sopenharmony_ci	if (ret)
104462306a36Sopenharmony_ci		return ret;
104562306a36Sopenharmony_ci	s->dbqtimer_tick = usecs;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	/* if successful, reread resulting dependent Timer values */
104862306a36Sopenharmony_ci	ret = t4_read_sge_dbqtimers(adap, ARRAY_SIZE(s->dbqtimer_val),
104962306a36Sopenharmony_ci				    s->dbqtimer_val);
105062306a36Sopenharmony_ci	return ret;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci/* Set the SGE Doorbell Queue Timer Value for the Ethernet TX Queues
105462306a36Sopenharmony_ci * associated with a Network Device.  There is a relatively small array of
105562306a36Sopenharmony_ci * possible Timer Values so we need to pick the closest value available.
105662306a36Sopenharmony_ci */
105762306a36Sopenharmony_cistatic int set_dbqtimer(struct net_device *dev, int usecs)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	int qix, timerix, min_timerix, delta, min_delta;
106062306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
106162306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
106262306a36Sopenharmony_ci	struct sge *s = &adap->sge;
106362306a36Sopenharmony_ci	struct sge_eth_txq *txq;
106462306a36Sopenharmony_ci	u32 param, val;
106562306a36Sopenharmony_ci	int ret;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_SGE_DBQ_TIMER))
106862306a36Sopenharmony_ci		return 0;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	/* Find the SGE Doorbell Timer Value that's closest to the requested
107162306a36Sopenharmony_ci	 * value.
107262306a36Sopenharmony_ci	 */
107362306a36Sopenharmony_ci	min_delta = INT_MAX;
107462306a36Sopenharmony_ci	min_timerix = 0;
107562306a36Sopenharmony_ci	for (timerix = 0; timerix < ARRAY_SIZE(s->dbqtimer_val); timerix++) {
107662306a36Sopenharmony_ci		delta = s->dbqtimer_val[timerix] - usecs;
107762306a36Sopenharmony_ci		if (delta < 0)
107862306a36Sopenharmony_ci			delta = -delta;
107962306a36Sopenharmony_ci		if (delta < min_delta) {
108062306a36Sopenharmony_ci			min_delta = delta;
108162306a36Sopenharmony_ci			min_timerix = timerix;
108262306a36Sopenharmony_ci		}
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* Return early if it's the same Timer Index we're already using.
108662306a36Sopenharmony_ci	 * We use the same Timer Index for all of the TX Queues for an
108762306a36Sopenharmony_ci	 * interface so it's only necessary to check the first one.
108862306a36Sopenharmony_ci	 */
108962306a36Sopenharmony_ci	txq = &s->ethtxq[pi->first_qset];
109062306a36Sopenharmony_ci	if (txq->dbqtimerix == min_timerix)
109162306a36Sopenharmony_ci		return 0;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	for (qix = 0; qix < pi->nqsets; qix++, txq++) {
109462306a36Sopenharmony_ci		if (adap->flags & CXGB4_FULL_INIT_DONE) {
109562306a36Sopenharmony_ci			param =
109662306a36Sopenharmony_ci			 (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) |
109762306a36Sopenharmony_ci			  FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_EQ_TIMERIX) |
109862306a36Sopenharmony_ci			  FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id));
109962306a36Sopenharmony_ci			val = min_timerix;
110062306a36Sopenharmony_ci			ret = t4_set_params(adap, adap->mbox, adap->pf, 0,
110162306a36Sopenharmony_ci					    1, &param, &val);
110262306a36Sopenharmony_ci			if (ret)
110362306a36Sopenharmony_ci				return ret;
110462306a36Sopenharmony_ci		}
110562306a36Sopenharmony_ci		txq->dbqtimerix = min_timerix;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci	return 0;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX
111162306a36Sopenharmony_ci * Queues and the Timer Value for the Ethernet TX Queues associated with a
111262306a36Sopenharmony_ci * Network Device.  Since changing the global Tick changes all of the
111362306a36Sopenharmony_ci * available Timer Values, we need to do this first before selecting the
111462306a36Sopenharmony_ci * resulting closest Timer Value.  Moreover, since the Tick is global,
111562306a36Sopenharmony_ci * changing it affects the Timer Values for all Network Devices on the
111662306a36Sopenharmony_ci * adapter.  So, before changing the Tick, we grab all of the current Timer
111762306a36Sopenharmony_ci * Values for other Network Devices on this Adapter and then attempt to select
111862306a36Sopenharmony_ci * new Timer Values which are close to the old values ...
111962306a36Sopenharmony_ci */
112062306a36Sopenharmony_cistatic int set_dbqtimer_tickval(struct net_device *dev,
112162306a36Sopenharmony_ci				int tick_usecs, int timer_usecs)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
112462306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
112562306a36Sopenharmony_ci	int timer[MAX_NPORTS];
112662306a36Sopenharmony_ci	unsigned int port;
112762306a36Sopenharmony_ci	int ret;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* Grab the other adapter Network Interface current timers and fill in
113062306a36Sopenharmony_ci	 * the new one for this Network Interface.
113162306a36Sopenharmony_ci	 */
113262306a36Sopenharmony_ci	for_each_port(adap, port)
113362306a36Sopenharmony_ci		if (port == pi->port_id)
113462306a36Sopenharmony_ci			timer[port] = timer_usecs;
113562306a36Sopenharmony_ci		else
113662306a36Sopenharmony_ci			timer[port] = get_dbqtimer(adap->port[port]);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/* Change the global Tick first ... */
113962306a36Sopenharmony_ci	ret = set_dbqtimer_tick(dev, tick_usecs);
114062306a36Sopenharmony_ci	if (ret)
114162306a36Sopenharmony_ci		return ret;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	/* ... and then set all of the Network Interface Timer Values ... */
114462306a36Sopenharmony_ci	for_each_port(adap, port) {
114562306a36Sopenharmony_ci		ret = set_dbqtimer(adap->port[port], timer[port]);
114662306a36Sopenharmony_ci		if (ret)
114762306a36Sopenharmony_ci			return ret;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return 0;
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic int set_coalesce(struct net_device *dev,
115462306a36Sopenharmony_ci			struct ethtool_coalesce *coalesce,
115562306a36Sopenharmony_ci			struct kernel_ethtool_coalesce *kernel_coal,
115662306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	int ret;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	set_adaptive_rx_setting(dev, coalesce->use_adaptive_rx_coalesce);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	ret = set_rx_intr_params(dev, coalesce->rx_coalesce_usecs,
116362306a36Sopenharmony_ci				 coalesce->rx_max_coalesced_frames);
116462306a36Sopenharmony_ci	if (ret)
116562306a36Sopenharmony_ci		return ret;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	return set_dbqtimer_tickval(dev,
116862306a36Sopenharmony_ci				    coalesce->tx_coalesce_usecs_irq,
116962306a36Sopenharmony_ci				    coalesce->tx_coalesce_usecs);
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c,
117362306a36Sopenharmony_ci			struct kernel_ethtool_coalesce *kernel_coal,
117462306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
117762306a36Sopenharmony_ci	const struct adapter *adap = pi->adapter;
117862306a36Sopenharmony_ci	const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	c->rx_coalesce_usecs = qtimer_val(adap, rq);
118162306a36Sopenharmony_ci	c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ?
118262306a36Sopenharmony_ci		adap->sge.counter_val[rq->pktcnt_idx] : 0;
118362306a36Sopenharmony_ci	c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev);
118462306a36Sopenharmony_ci	c->tx_coalesce_usecs_irq = get_dbqtimer_tick(dev);
118562306a36Sopenharmony_ci	c->tx_coalesce_usecs = get_dbqtimer(dev);
118662306a36Sopenharmony_ci	return 0;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci/* The next two routines implement eeprom read/write from physical addresses.
119062306a36Sopenharmony_ci */
119162306a36Sopenharmony_cistatic int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (vaddr >= 0)
119662306a36Sopenharmony_ci		vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v);
119762306a36Sopenharmony_ci	return vaddr < 0 ? vaddr : 0;
119862306a36Sopenharmony_ci}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (vaddr >= 0)
120562306a36Sopenharmony_ci		vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v);
120662306a36Sopenharmony_ci	return vaddr < 0 ? vaddr : 0;
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci#define EEPROM_MAGIC 0x38E2F10C
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
121262306a36Sopenharmony_ci		      u8 *data)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	int i, err = 0;
121562306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
121662306a36Sopenharmony_ci	u8 *buf = kvzalloc(EEPROMSIZE, GFP_KERNEL);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	if (!buf)
121962306a36Sopenharmony_ci		return -ENOMEM;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	e->magic = EEPROM_MAGIC;
122262306a36Sopenharmony_ci	for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
122362306a36Sopenharmony_ci		err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	if (!err)
122662306a36Sopenharmony_ci		memcpy(data, buf + e->offset, e->len);
122762306a36Sopenharmony_ci	kvfree(buf);
122862306a36Sopenharmony_ci	return err;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_cistatic int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
123262306a36Sopenharmony_ci		      u8 *data)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	u8 *buf;
123562306a36Sopenharmony_ci	int err = 0;
123662306a36Sopenharmony_ci	u32 aligned_offset, aligned_len, *p;
123762306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (eeprom->magic != EEPROM_MAGIC)
124062306a36Sopenharmony_ci		return -EINVAL;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	aligned_offset = eeprom->offset & ~3;
124362306a36Sopenharmony_ci	aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (adapter->pf > 0) {
124662306a36Sopenharmony_ci		u32 start = 1024 + adapter->pf * EEPROMPFSIZE;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci		if (aligned_offset < start ||
124962306a36Sopenharmony_ci		    aligned_offset + aligned_len > start + EEPROMPFSIZE)
125062306a36Sopenharmony_ci			return -EPERM;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
125462306a36Sopenharmony_ci		/* RMW possibly needed for first or last words.
125562306a36Sopenharmony_ci		 */
125662306a36Sopenharmony_ci		buf = kvzalloc(aligned_len, GFP_KERNEL);
125762306a36Sopenharmony_ci		if (!buf)
125862306a36Sopenharmony_ci			return -ENOMEM;
125962306a36Sopenharmony_ci		err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf);
126062306a36Sopenharmony_ci		if (!err && aligned_len > 4)
126162306a36Sopenharmony_ci			err = eeprom_rd_phys(adapter,
126262306a36Sopenharmony_ci					     aligned_offset + aligned_len - 4,
126362306a36Sopenharmony_ci					     (u32 *)&buf[aligned_len - 4]);
126462306a36Sopenharmony_ci		if (err)
126562306a36Sopenharmony_ci			goto out;
126662306a36Sopenharmony_ci		memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
126762306a36Sopenharmony_ci	} else {
126862306a36Sopenharmony_ci		buf = data;
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	err = t4_seeprom_wp(adapter, false);
127262306a36Sopenharmony_ci	if (err)
127362306a36Sopenharmony_ci		goto out;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
127662306a36Sopenharmony_ci		err = eeprom_wr_phys(adapter, aligned_offset, *p);
127762306a36Sopenharmony_ci		aligned_offset += 4;
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (!err)
128162306a36Sopenharmony_ci		err = t4_seeprom_wp(adapter, true);
128262306a36Sopenharmony_ciout:
128362306a36Sopenharmony_ci	if (buf != data)
128462306a36Sopenharmony_ci		kvfree(buf);
128562306a36Sopenharmony_ci	return err;
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_cistatic int cxgb4_ethtool_flash_bootcfg(struct net_device *netdev,
128962306a36Sopenharmony_ci				       const u8 *data, u32 size)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
129262306a36Sopenharmony_ci	int ret;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	ret = t4_load_bootcfg(adap, data, size);
129562306a36Sopenharmony_ci	if (ret)
129662306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "Failed to load boot cfg image\n");
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	return ret;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_cistatic int cxgb4_ethtool_flash_boot(struct net_device *netdev,
130262306a36Sopenharmony_ci				    const u8 *bdata, u32 size)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
130562306a36Sopenharmony_ci	unsigned int offset;
130662306a36Sopenharmony_ci	u8 *data;
130762306a36Sopenharmony_ci	int ret;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	data = kmemdup(bdata, size, GFP_KERNEL);
131062306a36Sopenharmony_ci	if (!data)
131162306a36Sopenharmony_ci		return -ENOMEM;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	offset = OFFSET_G(t4_read_reg(adap, PF_REG(0, PCIE_PF_EXPROM_OFST_A)));
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	ret = t4_load_boot(adap, data, offset, size);
131662306a36Sopenharmony_ci	if (ret)
131762306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "Failed to load boot image\n");
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	kfree(data);
132062306a36Sopenharmony_ci	return ret;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci#define CXGB4_PHY_SIG 0x130000ea
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic int cxgb4_validate_phy_image(const u8 *data, u32 *size)
132662306a36Sopenharmony_ci{
132762306a36Sopenharmony_ci	struct cxgb4_fw_data *header;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	header = (struct cxgb4_fw_data *)data;
133062306a36Sopenharmony_ci	if (be32_to_cpu(header->signature) != CXGB4_PHY_SIG)
133162306a36Sopenharmony_ci		return -EINVAL;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	return 0;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic int cxgb4_ethtool_flash_phy(struct net_device *netdev,
133762306a36Sopenharmony_ci				   const u8 *data, u32 size)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
134062306a36Sopenharmony_ci	int ret;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	ret = cxgb4_validate_phy_image(data, NULL);
134362306a36Sopenharmony_ci	if (ret) {
134462306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "PHY signature mismatch\n");
134562306a36Sopenharmony_ci		return ret;
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	/* We have to RESET the chip/firmware because we need the
134962306a36Sopenharmony_ci	 * chip in uninitialized state for loading new PHY image.
135062306a36Sopenharmony_ci	 * Otherwise, the running firmware will only store the PHY
135162306a36Sopenharmony_ci	 * image in local RAM which will be lost after next reset.
135262306a36Sopenharmony_ci	 */
135362306a36Sopenharmony_ci	ret = t4_fw_reset(adap, adap->mbox, PIORSTMODE_F | PIORST_F);
135462306a36Sopenharmony_ci	if (ret < 0) {
135562306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
135662306a36Sopenharmony_ci			"Set FW to RESET for flashing PHY FW failed. ret: %d\n",
135762306a36Sopenharmony_ci			ret);
135862306a36Sopenharmony_ci		return ret;
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	ret = t4_load_phy_fw(adap, MEMWIN_NIC, NULL, data, size);
136262306a36Sopenharmony_ci	if (ret < 0) {
136362306a36Sopenharmony_ci		dev_err(adap->pdev_dev, "Failed to load PHY FW. ret: %d\n",
136462306a36Sopenharmony_ci			ret);
136562306a36Sopenharmony_ci		return ret;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	return 0;
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cistatic int cxgb4_ethtool_flash_fw(struct net_device *netdev,
137262306a36Sopenharmony_ci				  const u8 *data, u32 size)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
137562306a36Sopenharmony_ci	unsigned int mbox = PCIE_FW_MASTER_M + 1;
137662306a36Sopenharmony_ci	int ret;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	/* If the adapter has been fully initialized then we'll go ahead and
137962306a36Sopenharmony_ci	 * try to get the firmware's cooperation in upgrading to the new
138062306a36Sopenharmony_ci	 * firmware image otherwise we'll try to do the entire job from the
138162306a36Sopenharmony_ci	 * host ... and we always "force" the operation in this path.
138262306a36Sopenharmony_ci	 */
138362306a36Sopenharmony_ci	if (adap->flags & CXGB4_FULL_INIT_DONE)
138462306a36Sopenharmony_ci		mbox = adap->mbox;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	ret = t4_fw_upgrade(adap, mbox, data, size, 1);
138762306a36Sopenharmony_ci	if (ret)
138862306a36Sopenharmony_ci		dev_err(adap->pdev_dev,
138962306a36Sopenharmony_ci			"Failed to flash firmware\n");
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	return ret;
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_cistatic int cxgb4_ethtool_flash_region(struct net_device *netdev,
139562306a36Sopenharmony_ci				      const u8 *data, u32 size, u32 region)
139662306a36Sopenharmony_ci{
139762306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
139862306a36Sopenharmony_ci	int ret;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	switch (region) {
140162306a36Sopenharmony_ci	case CXGB4_ETHTOOL_FLASH_FW:
140262306a36Sopenharmony_ci		ret = cxgb4_ethtool_flash_fw(netdev, data, size);
140362306a36Sopenharmony_ci		break;
140462306a36Sopenharmony_ci	case CXGB4_ETHTOOL_FLASH_PHY:
140562306a36Sopenharmony_ci		ret = cxgb4_ethtool_flash_phy(netdev, data, size);
140662306a36Sopenharmony_ci		break;
140762306a36Sopenharmony_ci	case CXGB4_ETHTOOL_FLASH_BOOT:
140862306a36Sopenharmony_ci		ret = cxgb4_ethtool_flash_boot(netdev, data, size);
140962306a36Sopenharmony_ci		break;
141062306a36Sopenharmony_ci	case CXGB4_ETHTOOL_FLASH_BOOTCFG:
141162306a36Sopenharmony_ci		ret = cxgb4_ethtool_flash_bootcfg(netdev, data, size);
141262306a36Sopenharmony_ci		break;
141362306a36Sopenharmony_ci	default:
141462306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
141562306a36Sopenharmony_ci		break;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	if (!ret)
141962306a36Sopenharmony_ci		dev_info(adap->pdev_dev,
142062306a36Sopenharmony_ci			 "loading %s successful, reload cxgb4 driver\n",
142162306a36Sopenharmony_ci			 flash_region_strings[region]);
142262306a36Sopenharmony_ci	return ret;
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci#define CXGB4_FW_SIG 0x4368656c
142662306a36Sopenharmony_ci#define CXGB4_FW_SIG_OFFSET 0x160
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int cxgb4_validate_fw_image(const u8 *data, u32 *size)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	struct cxgb4_fw_data *header;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	header = (struct cxgb4_fw_data *)&data[CXGB4_FW_SIG_OFFSET];
143362306a36Sopenharmony_ci	if (be32_to_cpu(header->signature) != CXGB4_FW_SIG)
143462306a36Sopenharmony_ci		return -EINVAL;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (size)
143762306a36Sopenharmony_ci		*size = be16_to_cpu(((struct fw_hdr *)data)->len512) * 512;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	return 0;
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_cistatic int cxgb4_validate_bootcfg_image(const u8 *data, u32 *size)
144362306a36Sopenharmony_ci{
144462306a36Sopenharmony_ci	struct cxgb4_bootcfg_data *header;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	header = (struct cxgb4_bootcfg_data *)data;
144762306a36Sopenharmony_ci	if (le16_to_cpu(header->signature) != BOOT_CFG_SIG)
144862306a36Sopenharmony_ci		return -EINVAL;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	return 0;
145162306a36Sopenharmony_ci}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_cistatic int cxgb4_validate_boot_image(const u8 *data, u32 *size)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	struct cxgb4_pci_exp_rom_header *exp_header;
145662306a36Sopenharmony_ci	struct cxgb4_pcir_data *pcir_header;
145762306a36Sopenharmony_ci	struct legacy_pci_rom_hdr *header;
145862306a36Sopenharmony_ci	const u8 *cur_header = data;
145962306a36Sopenharmony_ci	u16 pcir_offset;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	exp_header = (struct cxgb4_pci_exp_rom_header *)data;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (le16_to_cpu(exp_header->signature) != BOOT_SIGNATURE)
146462306a36Sopenharmony_ci		return -EINVAL;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (size) {
146762306a36Sopenharmony_ci		do {
146862306a36Sopenharmony_ci			header = (struct legacy_pci_rom_hdr *)cur_header;
146962306a36Sopenharmony_ci			pcir_offset = le16_to_cpu(header->pcir_offset);
147062306a36Sopenharmony_ci			pcir_header = (struct cxgb4_pcir_data *)(cur_header +
147162306a36Sopenharmony_ci				      pcir_offset);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci			*size += header->size512 * 512;
147462306a36Sopenharmony_ci			cur_header += header->size512 * 512;
147562306a36Sopenharmony_ci		} while (!(pcir_header->indicator & CXGB4_HDR_INDI));
147662306a36Sopenharmony_ci	}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	return 0;
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_cistatic int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size)
148262306a36Sopenharmony_ci{
148362306a36Sopenharmony_ci	if (!cxgb4_validate_fw_image(data, size))
148462306a36Sopenharmony_ci		return CXGB4_ETHTOOL_FLASH_FW;
148562306a36Sopenharmony_ci	if (!cxgb4_validate_boot_image(data, size))
148662306a36Sopenharmony_ci		return CXGB4_ETHTOOL_FLASH_BOOT;
148762306a36Sopenharmony_ci	if (!cxgb4_validate_phy_image(data, size))
148862306a36Sopenharmony_ci		return CXGB4_ETHTOOL_FLASH_PHY;
148962306a36Sopenharmony_ci	if (!cxgb4_validate_bootcfg_image(data, size))
149062306a36Sopenharmony_ci		return CXGB4_ETHTOOL_FLASH_BOOTCFG;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	return -EOPNOTSUPP;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_cistatic int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(netdev);
149862306a36Sopenharmony_ci	const struct firmware *fw;
149962306a36Sopenharmony_ci	unsigned int master;
150062306a36Sopenharmony_ci	u8 master_vld = 0;
150162306a36Sopenharmony_ci	const u8 *fw_data;
150262306a36Sopenharmony_ci	size_t fw_size;
150362306a36Sopenharmony_ci	u32 size = 0;
150462306a36Sopenharmony_ci	u32 pcie_fw;
150562306a36Sopenharmony_ci	int region;
150662306a36Sopenharmony_ci	int ret;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	pcie_fw = t4_read_reg(adap, PCIE_FW_A);
150962306a36Sopenharmony_ci	master = PCIE_FW_MASTER_G(pcie_fw);
151062306a36Sopenharmony_ci	if (pcie_fw & PCIE_FW_MASTER_VLD_F)
151162306a36Sopenharmony_ci		master_vld = 1;
151262306a36Sopenharmony_ci	/* if csiostor is the master return */
151362306a36Sopenharmony_ci	if (master_vld && (master != adap->pf)) {
151462306a36Sopenharmony_ci		dev_warn(adap->pdev_dev,
151562306a36Sopenharmony_ci			 "cxgb4 driver needs to be loaded as MASTER to support FW flash\n");
151662306a36Sopenharmony_ci		return -EOPNOTSUPP;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	ef->data[sizeof(ef->data) - 1] = '\0';
152062306a36Sopenharmony_ci	ret = request_firmware(&fw, ef->data, adap->pdev_dev);
152162306a36Sopenharmony_ci	if (ret < 0)
152262306a36Sopenharmony_ci		return ret;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	fw_data = fw->data;
152562306a36Sopenharmony_ci	fw_size = fw->size;
152662306a36Sopenharmony_ci	if (ef->region == ETHTOOL_FLASH_ALL_REGIONS) {
152762306a36Sopenharmony_ci		while (fw_size > 0) {
152862306a36Sopenharmony_ci			size = 0;
152962306a36Sopenharmony_ci			region = cxgb4_ethtool_get_flash_region(fw_data, &size);
153062306a36Sopenharmony_ci			if (region < 0 || !size) {
153162306a36Sopenharmony_ci				ret = region;
153262306a36Sopenharmony_ci				goto out_free_fw;
153362306a36Sopenharmony_ci			}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci			ret = cxgb4_ethtool_flash_region(netdev, fw_data, size,
153662306a36Sopenharmony_ci							 region);
153762306a36Sopenharmony_ci			if (ret)
153862306a36Sopenharmony_ci				goto out_free_fw;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci			fw_data += size;
154162306a36Sopenharmony_ci			fw_size -= size;
154262306a36Sopenharmony_ci		}
154362306a36Sopenharmony_ci	} else {
154462306a36Sopenharmony_ci		ret = cxgb4_ethtool_flash_region(netdev, fw_data, fw_size,
154562306a36Sopenharmony_ci						 ef->region);
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ciout_free_fw:
154962306a36Sopenharmony_ci	release_firmware(fw);
155062306a36Sopenharmony_ci	return ret;
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cistatic int get_ts_info(struct net_device *dev, struct ethtool_ts_info *ts_info)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
155662306a36Sopenharmony_ci	struct  adapter *adapter = pi->adapter;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
155962306a36Sopenharmony_ci				   SOF_TIMESTAMPING_RX_SOFTWARE |
156062306a36Sopenharmony_ci				   SOF_TIMESTAMPING_SOFTWARE;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	ts_info->so_timestamping |= SOF_TIMESTAMPING_RX_HARDWARE |
156362306a36Sopenharmony_ci				    SOF_TIMESTAMPING_TX_HARDWARE |
156462306a36Sopenharmony_ci				    SOF_TIMESTAMPING_RAW_HARDWARE;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) |
156762306a36Sopenharmony_ci			    (1 << HWTSTAMP_TX_ON);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
157062306a36Sopenharmony_ci			      (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
157162306a36Sopenharmony_ci			      (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
157262306a36Sopenharmony_ci			      (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
157362306a36Sopenharmony_ci			      (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
157462306a36Sopenharmony_ci			      (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (adapter->ptp_clock)
157762306a36Sopenharmony_ci		ts_info->phc_index = ptp_clock_index(adapter->ptp_clock);
157862306a36Sopenharmony_ci	else
157962306a36Sopenharmony_ci		ts_info->phc_index = -1;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	return 0;
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic u32 get_rss_table_size(struct net_device *dev)
158562306a36Sopenharmony_ci{
158662306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	return pi->rss_size;
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc)
159262306a36Sopenharmony_ci{
159362306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
159462306a36Sopenharmony_ci	unsigned int n = pi->rss_size;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	if (hfunc)
159762306a36Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
159862306a36Sopenharmony_ci	if (!p)
159962306a36Sopenharmony_ci		return 0;
160062306a36Sopenharmony_ci	while (n--)
160162306a36Sopenharmony_ci		p[n] = pi->rss[n];
160262306a36Sopenharmony_ci	return 0;
160362306a36Sopenharmony_ci}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_cistatic int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key,
160662306a36Sopenharmony_ci			 const u8 hfunc)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	unsigned int i;
160962306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/* We require at least one supported parameter to be changed and no
161262306a36Sopenharmony_ci	 * change in any of the unsupported parameters
161362306a36Sopenharmony_ci	 */
161462306a36Sopenharmony_ci	if (key ||
161562306a36Sopenharmony_ci	    (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
161662306a36Sopenharmony_ci		return -EOPNOTSUPP;
161762306a36Sopenharmony_ci	if (!p)
161862306a36Sopenharmony_ci		return 0;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* Interface must be brought up atleast once */
162162306a36Sopenharmony_ci	if (pi->adapter->flags & CXGB4_FULL_INIT_DONE) {
162262306a36Sopenharmony_ci		for (i = 0; i < pi->rss_size; i++)
162362306a36Sopenharmony_ci			pi->rss[i] = p[i];
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci		return cxgb4_write_rss(pi, pi->rss);
162662306a36Sopenharmony_ci	}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	return -EPERM;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_cistatic struct filter_entry *cxgb4_get_filter_entry(struct adapter *adap,
163262306a36Sopenharmony_ci						   u32 ftid)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	struct tid_info *t = &adap->tids;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	if (ftid >= t->hpftid_base && ftid < t->hpftid_base + t->nhpftids)
163762306a36Sopenharmony_ci		return &t->hpftid_tab[ftid - t->hpftid_base];
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (ftid >= t->ftid_base && ftid < t->ftid_base + t->nftids)
164062306a36Sopenharmony_ci		return &t->ftid_tab[ftid - t->ftid_base];
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	return lookup_tid(t, ftid);
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic void cxgb4_fill_filter_rule(struct ethtool_rx_flow_spec *fs,
164662306a36Sopenharmony_ci				   struct ch_filter_specification *dfs)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	switch (dfs->val.proto) {
164962306a36Sopenharmony_ci	case IPPROTO_TCP:
165062306a36Sopenharmony_ci		if (dfs->type)
165162306a36Sopenharmony_ci			fs->flow_type = TCP_V6_FLOW;
165262306a36Sopenharmony_ci		else
165362306a36Sopenharmony_ci			fs->flow_type = TCP_V4_FLOW;
165462306a36Sopenharmony_ci		break;
165562306a36Sopenharmony_ci	case IPPROTO_UDP:
165662306a36Sopenharmony_ci		if (dfs->type)
165762306a36Sopenharmony_ci			fs->flow_type = UDP_V6_FLOW;
165862306a36Sopenharmony_ci		else
165962306a36Sopenharmony_ci			fs->flow_type = UDP_V4_FLOW;
166062306a36Sopenharmony_ci		break;
166162306a36Sopenharmony_ci	}
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	if (dfs->type) {
166462306a36Sopenharmony_ci		fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->val.fport);
166562306a36Sopenharmony_ci		fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->mask.fport);
166662306a36Sopenharmony_ci		fs->h_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->val.lport);
166762306a36Sopenharmony_ci		fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->mask.lport);
166862306a36Sopenharmony_ci		memcpy(&fs->h_u.tcp_ip6_spec.ip6src, &dfs->val.fip[0],
166962306a36Sopenharmony_ci		       sizeof(fs->h_u.tcp_ip6_spec.ip6src));
167062306a36Sopenharmony_ci		memcpy(&fs->m_u.tcp_ip6_spec.ip6src, &dfs->mask.fip[0],
167162306a36Sopenharmony_ci		       sizeof(fs->m_u.tcp_ip6_spec.ip6src));
167262306a36Sopenharmony_ci		memcpy(&fs->h_u.tcp_ip6_spec.ip6dst, &dfs->val.lip[0],
167362306a36Sopenharmony_ci		       sizeof(fs->h_u.tcp_ip6_spec.ip6dst));
167462306a36Sopenharmony_ci		memcpy(&fs->m_u.tcp_ip6_spec.ip6dst, &dfs->mask.lip[0],
167562306a36Sopenharmony_ci		       sizeof(fs->m_u.tcp_ip6_spec.ip6dst));
167662306a36Sopenharmony_ci		fs->h_u.tcp_ip6_spec.tclass = dfs->val.tos;
167762306a36Sopenharmony_ci		fs->m_u.tcp_ip6_spec.tclass = dfs->mask.tos;
167862306a36Sopenharmony_ci	} else {
167962306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->val.fport);
168062306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->mask.fport);
168162306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->val.lport);
168262306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->mask.lport);
168362306a36Sopenharmony_ci		memcpy(&fs->h_u.tcp_ip4_spec.ip4src, &dfs->val.fip[0],
168462306a36Sopenharmony_ci		       sizeof(fs->h_u.tcp_ip4_spec.ip4src));
168562306a36Sopenharmony_ci		memcpy(&fs->m_u.tcp_ip4_spec.ip4src, &dfs->mask.fip[0],
168662306a36Sopenharmony_ci		       sizeof(fs->m_u.tcp_ip4_spec.ip4src));
168762306a36Sopenharmony_ci		memcpy(&fs->h_u.tcp_ip4_spec.ip4dst, &dfs->val.lip[0],
168862306a36Sopenharmony_ci		       sizeof(fs->h_u.tcp_ip4_spec.ip4dst));
168962306a36Sopenharmony_ci		memcpy(&fs->m_u.tcp_ip4_spec.ip4dst, &dfs->mask.lip[0],
169062306a36Sopenharmony_ci		       sizeof(fs->m_u.tcp_ip4_spec.ip4dst));
169162306a36Sopenharmony_ci		fs->h_u.tcp_ip4_spec.tos = dfs->val.tos;
169262306a36Sopenharmony_ci		fs->m_u.tcp_ip4_spec.tos = dfs->mask.tos;
169362306a36Sopenharmony_ci	}
169462306a36Sopenharmony_ci	fs->h_ext.vlan_tci = cpu_to_be16(dfs->val.ivlan);
169562306a36Sopenharmony_ci	fs->m_ext.vlan_tci = cpu_to_be16(dfs->mask.ivlan);
169662306a36Sopenharmony_ci	fs->flow_type |= FLOW_EXT;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	if (dfs->action == FILTER_DROP)
169962306a36Sopenharmony_ci		fs->ring_cookie = RX_CLS_FLOW_DISC;
170062306a36Sopenharmony_ci	else
170162306a36Sopenharmony_ci		fs->ring_cookie = dfs->iq;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistatic int cxgb4_ntuple_get_filter(struct net_device *dev,
170562306a36Sopenharmony_ci				   struct ethtool_rxnfc *cmd,
170662306a36Sopenharmony_ci				   unsigned int loc)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
170962306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
171062306a36Sopenharmony_ci	struct filter_entry *f;
171162306a36Sopenharmony_ci	int ftid;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_FULL_INIT_DONE))
171462306a36Sopenharmony_ci		return -EAGAIN;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	/* Check for maximum filter range */
171762306a36Sopenharmony_ci	if (!adap->ethtool_filters)
171862306a36Sopenharmony_ci		return -EOPNOTSUPP;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (loc >= adap->ethtool_filters->nentries)
172162306a36Sopenharmony_ci		return -ERANGE;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (!test_bit(loc, adap->ethtool_filters->port[pi->port_id].bmap))
172462306a36Sopenharmony_ci		return -ENOENT;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	ftid = adap->ethtool_filters->port[pi->port_id].loc_array[loc];
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/* Fetch filter_entry */
172962306a36Sopenharmony_ci	f = cxgb4_get_filter_entry(adap, ftid);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	cxgb4_fill_filter_rule(&cmd->fs, &f->fs);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	return 0;
173462306a36Sopenharmony_ci}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_cistatic int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
173762306a36Sopenharmony_ci		     u32 *rules)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
174062306a36Sopenharmony_ci	struct adapter *adap = netdev2adap(dev);
174162306a36Sopenharmony_ci	unsigned int count = 0, index = 0;
174262306a36Sopenharmony_ci	int ret = 0;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	switch (info->cmd) {
174562306a36Sopenharmony_ci	case ETHTOOL_GRXFH: {
174662306a36Sopenharmony_ci		unsigned int v = pi->rss_mode;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci		info->data = 0;
174962306a36Sopenharmony_ci		switch (info->flow_type) {
175062306a36Sopenharmony_ci		case TCP_V4_FLOW:
175162306a36Sopenharmony_ci			if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F)
175262306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST |
175362306a36Sopenharmony_ci					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
175462306a36Sopenharmony_ci			else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F)
175562306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST;
175662306a36Sopenharmony_ci			break;
175762306a36Sopenharmony_ci		case UDP_V4_FLOW:
175862306a36Sopenharmony_ci			if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) &&
175962306a36Sopenharmony_ci			    (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F))
176062306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST |
176162306a36Sopenharmony_ci					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
176262306a36Sopenharmony_ci			else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F)
176362306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST;
176462306a36Sopenharmony_ci			break;
176562306a36Sopenharmony_ci		case SCTP_V4_FLOW:
176662306a36Sopenharmony_ci		case AH_ESP_V4_FLOW:
176762306a36Sopenharmony_ci		case IPV4_FLOW:
176862306a36Sopenharmony_ci			if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F)
176962306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST;
177062306a36Sopenharmony_ci			break;
177162306a36Sopenharmony_ci		case TCP_V6_FLOW:
177262306a36Sopenharmony_ci			if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F)
177362306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST |
177462306a36Sopenharmony_ci					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
177562306a36Sopenharmony_ci			else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F)
177662306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST;
177762306a36Sopenharmony_ci			break;
177862306a36Sopenharmony_ci		case UDP_V6_FLOW:
177962306a36Sopenharmony_ci			if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) &&
178062306a36Sopenharmony_ci			    (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F))
178162306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST |
178262306a36Sopenharmony_ci					     RXH_L4_B_0_1 | RXH_L4_B_2_3;
178362306a36Sopenharmony_ci			else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F)
178462306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST;
178562306a36Sopenharmony_ci			break;
178662306a36Sopenharmony_ci		case SCTP_V6_FLOW:
178762306a36Sopenharmony_ci		case AH_ESP_V6_FLOW:
178862306a36Sopenharmony_ci		case IPV6_FLOW:
178962306a36Sopenharmony_ci			if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F)
179062306a36Sopenharmony_ci				info->data = RXH_IP_SRC | RXH_IP_DST;
179162306a36Sopenharmony_ci			break;
179262306a36Sopenharmony_ci		}
179362306a36Sopenharmony_ci		return 0;
179462306a36Sopenharmony_ci	}
179562306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
179662306a36Sopenharmony_ci		info->data = pi->nqsets;
179762306a36Sopenharmony_ci		return 0;
179862306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
179962306a36Sopenharmony_ci		info->rule_cnt =
180062306a36Sopenharmony_ci		       adap->ethtool_filters->port[pi->port_id].in_use;
180162306a36Sopenharmony_ci		return 0;
180262306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
180362306a36Sopenharmony_ci		return cxgb4_ntuple_get_filter(dev, info, info->fs.location);
180462306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
180562306a36Sopenharmony_ci		info->data = adap->ethtool_filters->nentries;
180662306a36Sopenharmony_ci		while (count < info->rule_cnt) {
180762306a36Sopenharmony_ci			ret = cxgb4_ntuple_get_filter(dev, info, index);
180862306a36Sopenharmony_ci			if (!ret)
180962306a36Sopenharmony_ci				rules[count++] = index;
181062306a36Sopenharmony_ci			index++;
181162306a36Sopenharmony_ci		}
181262306a36Sopenharmony_ci		return 0;
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	return -EOPNOTSUPP;
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_cistatic int cxgb4_ntuple_del_filter(struct net_device *dev,
181962306a36Sopenharmony_ci				   struct ethtool_rxnfc *cmd)
182062306a36Sopenharmony_ci{
182162306a36Sopenharmony_ci	struct cxgb4_ethtool_filter_info *filter_info;
182262306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
182362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
182462306a36Sopenharmony_ci	struct filter_entry *f;
182562306a36Sopenharmony_ci	u32 filter_id;
182662306a36Sopenharmony_ci	int ret;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	if (!(adapter->flags & CXGB4_FULL_INIT_DONE))
182962306a36Sopenharmony_ci		return -EAGAIN;  /* can still change nfilters */
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	if (!adapter->ethtool_filters)
183262306a36Sopenharmony_ci		return -EOPNOTSUPP;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	if (cmd->fs.location >= adapter->ethtool_filters->nentries) {
183562306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
183662306a36Sopenharmony_ci			"Location must be < %u",
183762306a36Sopenharmony_ci			adapter->ethtool_filters->nentries);
183862306a36Sopenharmony_ci		return -ERANGE;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	filter_info = &adapter->ethtool_filters->port[pi->port_id];
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	if (!test_bit(cmd->fs.location, filter_info->bmap))
184462306a36Sopenharmony_ci		return -ENOENT;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	filter_id = filter_info->loc_array[cmd->fs.location];
184762306a36Sopenharmony_ci	f = cxgb4_get_filter_entry(adapter, filter_id);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	if (f->fs.prio)
185062306a36Sopenharmony_ci		filter_id -= adapter->tids.hpftid_base;
185162306a36Sopenharmony_ci	else if (!f->fs.hash)
185262306a36Sopenharmony_ci		filter_id -= (adapter->tids.ftid_base - adapter->tids.nhpftids);
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	ret = cxgb4_flow_rule_destroy(dev, f->fs.tc_prio, &f->fs, filter_id);
185562306a36Sopenharmony_ci	if (ret)
185662306a36Sopenharmony_ci		goto err;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	clear_bit(cmd->fs.location, filter_info->bmap);
185962306a36Sopenharmony_ci	filter_info->in_use--;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cierr:
186262306a36Sopenharmony_ci	return ret;
186362306a36Sopenharmony_ci}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci/* Add Ethtool n-tuple filters. */
186662306a36Sopenharmony_cistatic int cxgb4_ntuple_set_filter(struct net_device *netdev,
186762306a36Sopenharmony_ci				   struct ethtool_rxnfc *cmd)
186862306a36Sopenharmony_ci{
186962306a36Sopenharmony_ci	struct ethtool_rx_flow_spec_input input = {};
187062306a36Sopenharmony_ci	struct cxgb4_ethtool_filter_info *filter_info;
187162306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(netdev);
187262306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
187362306a36Sopenharmony_ci	struct ch_filter_specification fs;
187462306a36Sopenharmony_ci	struct ethtool_rx_flow_rule *flow;
187562306a36Sopenharmony_ci	u32 tid;
187662306a36Sopenharmony_ci	int ret;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	if (!(adapter->flags & CXGB4_FULL_INIT_DONE))
187962306a36Sopenharmony_ci		return -EAGAIN;  /* can still change nfilters */
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	if (!adapter->ethtool_filters)
188262306a36Sopenharmony_ci		return -EOPNOTSUPP;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	if (cmd->fs.location >= adapter->ethtool_filters->nentries) {
188562306a36Sopenharmony_ci		dev_err(adapter->pdev_dev,
188662306a36Sopenharmony_ci			"Location must be < %u",
188762306a36Sopenharmony_ci			adapter->ethtool_filters->nentries);
188862306a36Sopenharmony_ci		return -ERANGE;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	if (test_bit(cmd->fs.location,
189262306a36Sopenharmony_ci		     adapter->ethtool_filters->port[pi->port_id].bmap))
189362306a36Sopenharmony_ci		return -EEXIST;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	memset(&fs, 0, sizeof(fs));
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	input.fs = &cmd->fs;
189862306a36Sopenharmony_ci	flow = ethtool_rx_flow_rule_create(&input);
189962306a36Sopenharmony_ci	if (IS_ERR(flow)) {
190062306a36Sopenharmony_ci		ret = PTR_ERR(flow);
190162306a36Sopenharmony_ci		goto exit;
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	fs.hitcnts = 1;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	ret = cxgb4_flow_rule_replace(netdev, flow->rule, cmd->fs.location,
190762306a36Sopenharmony_ci				      NULL, &fs, &tid);
190862306a36Sopenharmony_ci	if (ret)
190962306a36Sopenharmony_ci		goto free;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	filter_info = &adapter->ethtool_filters->port[pi->port_id];
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (fs.prio)
191462306a36Sopenharmony_ci		tid += adapter->tids.hpftid_base;
191562306a36Sopenharmony_ci	else if (!fs.hash)
191662306a36Sopenharmony_ci		tid += (adapter->tids.ftid_base - adapter->tids.nhpftids);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	filter_info->loc_array[cmd->fs.location] = tid;
191962306a36Sopenharmony_ci	set_bit(cmd->fs.location, filter_info->bmap);
192062306a36Sopenharmony_ci	filter_info->in_use++;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_cifree:
192362306a36Sopenharmony_ci	ethtool_rx_flow_rule_destroy(flow);
192462306a36Sopenharmony_ciexit:
192562306a36Sopenharmony_ci	return ret;
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_cistatic int set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	switch (cmd->cmd) {
193362306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
193462306a36Sopenharmony_ci		ret = cxgb4_ntuple_set_filter(dev, cmd);
193562306a36Sopenharmony_ci		break;
193662306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
193762306a36Sopenharmony_ci		ret = cxgb4_ntuple_del_filter(dev, cmd);
193862306a36Sopenharmony_ci		break;
193962306a36Sopenharmony_ci	default:
194062306a36Sopenharmony_ci		break;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	return ret;
194462306a36Sopenharmony_ci}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_cistatic int set_dump(struct net_device *dev, struct ethtool_dump *eth_dump)
194762306a36Sopenharmony_ci{
194862306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
194962306a36Sopenharmony_ci	u32 len = 0;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	len = sizeof(struct cudbg_hdr) +
195262306a36Sopenharmony_ci	      sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY;
195362306a36Sopenharmony_ci	len += cxgb4_get_dump_length(adapter, eth_dump->flag);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	adapter->eth_dump.flag = eth_dump->flag;
195662306a36Sopenharmony_ci	adapter->eth_dump.len = len;
195762306a36Sopenharmony_ci	return 0;
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_cistatic int get_dump_flag(struct net_device *dev, struct ethtool_dump *eth_dump)
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	eth_dump->flag = adapter->eth_dump.flag;
196562306a36Sopenharmony_ci	eth_dump->len = adapter->eth_dump.len;
196662306a36Sopenharmony_ci	eth_dump->version = adapter->eth_dump.version;
196762306a36Sopenharmony_ci	return 0;
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_cistatic int get_dump_data(struct net_device *dev, struct ethtool_dump *eth_dump,
197162306a36Sopenharmony_ci			 void *buf)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	struct adapter *adapter = netdev2adap(dev);
197462306a36Sopenharmony_ci	u32 len = 0;
197562306a36Sopenharmony_ci	int ret = 0;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	if (adapter->eth_dump.flag == CXGB4_ETH_DUMP_NONE)
197862306a36Sopenharmony_ci		return -ENOENT;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	len = sizeof(struct cudbg_hdr) +
198162306a36Sopenharmony_ci	      sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY;
198262306a36Sopenharmony_ci	len += cxgb4_get_dump_length(adapter, adapter->eth_dump.flag);
198362306a36Sopenharmony_ci	if (eth_dump->len < len)
198462306a36Sopenharmony_ci		return -ENOMEM;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	ret = cxgb4_cudbg_collect(adapter, buf, &len, adapter->eth_dump.flag);
198762306a36Sopenharmony_ci	if (ret)
198862306a36Sopenharmony_ci		return ret;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	eth_dump->flag = adapter->eth_dump.flag;
199162306a36Sopenharmony_ci	eth_dump->len = len;
199262306a36Sopenharmony_ci	eth_dump->version = adapter->eth_dump.version;
199362306a36Sopenharmony_ci	return 0;
199462306a36Sopenharmony_ci}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_cistatic bool cxgb4_fw_mod_type_info_available(unsigned int fw_mod_type)
199762306a36Sopenharmony_ci{
199862306a36Sopenharmony_ci	/* Read port module EEPROM as long as it is plugged-in and
199962306a36Sopenharmony_ci	 * safe to read.
200062306a36Sopenharmony_ci	 */
200162306a36Sopenharmony_ci	return (fw_mod_type != FW_PORT_MOD_TYPE_NONE &&
200262306a36Sopenharmony_ci		fw_mod_type != FW_PORT_MOD_TYPE_ERROR);
200362306a36Sopenharmony_ci}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cistatic int cxgb4_get_module_info(struct net_device *dev,
200662306a36Sopenharmony_ci				 struct ethtool_modinfo *modinfo)
200762306a36Sopenharmony_ci{
200862306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
200962306a36Sopenharmony_ci	u8 sff8472_comp, sff_diag_type, sff_rev;
201062306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
201162306a36Sopenharmony_ci	int ret;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	if (!cxgb4_fw_mod_type_info_available(pi->mod_type))
201462306a36Sopenharmony_ci		return -EINVAL;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	switch (pi->port_type) {
201762306a36Sopenharmony_ci	case FW_PORT_TYPE_SFP:
201862306a36Sopenharmony_ci	case FW_PORT_TYPE_QSA:
201962306a36Sopenharmony_ci	case FW_PORT_TYPE_SFP28:
202062306a36Sopenharmony_ci		ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan,
202162306a36Sopenharmony_ci				I2C_DEV_ADDR_A0, SFF_8472_COMP_ADDR,
202262306a36Sopenharmony_ci				SFF_8472_COMP_LEN, &sff8472_comp);
202362306a36Sopenharmony_ci		if (ret)
202462306a36Sopenharmony_ci			return ret;
202562306a36Sopenharmony_ci		ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan,
202662306a36Sopenharmony_ci				I2C_DEV_ADDR_A0, SFP_DIAG_TYPE_ADDR,
202762306a36Sopenharmony_ci				SFP_DIAG_TYPE_LEN, &sff_diag_type);
202862306a36Sopenharmony_ci		if (ret)
202962306a36Sopenharmony_ci			return ret;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci		if (!sff8472_comp || (sff_diag_type & SFP_DIAG_ADDRMODE)) {
203262306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8079;
203362306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
203462306a36Sopenharmony_ci		} else {
203562306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8472;
203662306a36Sopenharmony_ci			if (sff_diag_type & SFP_DIAG_IMPLEMENTED)
203762306a36Sopenharmony_ci				modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
203862306a36Sopenharmony_ci			else
203962306a36Sopenharmony_ci				modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2;
204062306a36Sopenharmony_ci		}
204162306a36Sopenharmony_ci		break;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	case FW_PORT_TYPE_QSFP:
204462306a36Sopenharmony_ci	case FW_PORT_TYPE_QSFP_10G:
204562306a36Sopenharmony_ci	case FW_PORT_TYPE_CR_QSFP:
204662306a36Sopenharmony_ci	case FW_PORT_TYPE_CR2_QSFP:
204762306a36Sopenharmony_ci	case FW_PORT_TYPE_CR4_QSFP:
204862306a36Sopenharmony_ci		ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan,
204962306a36Sopenharmony_ci				I2C_DEV_ADDR_A0, SFF_REV_ADDR,
205062306a36Sopenharmony_ci				SFF_REV_LEN, &sff_rev);
205162306a36Sopenharmony_ci		/* For QSFP type ports, revision value >= 3
205262306a36Sopenharmony_ci		 * means the SFP is 8636 compliant.
205362306a36Sopenharmony_ci		 */
205462306a36Sopenharmony_ci		if (ret)
205562306a36Sopenharmony_ci			return ret;
205662306a36Sopenharmony_ci		if (sff_rev >= 0x3) {
205762306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8636;
205862306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
205962306a36Sopenharmony_ci		} else {
206062306a36Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8436;
206162306a36Sopenharmony_ci			modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
206262306a36Sopenharmony_ci		}
206362306a36Sopenharmony_ci		break;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	default:
206662306a36Sopenharmony_ci		return -EINVAL;
206762306a36Sopenharmony_ci	}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	return 0;
207062306a36Sopenharmony_ci}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_cistatic int cxgb4_get_module_eeprom(struct net_device *dev,
207362306a36Sopenharmony_ci				   struct ethtool_eeprom *eprom, u8 *data)
207462306a36Sopenharmony_ci{
207562306a36Sopenharmony_ci	int ret = 0, offset = eprom->offset, len = eprom->len;
207662306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(dev);
207762306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	memset(data, 0, eprom->len);
208062306a36Sopenharmony_ci	if (offset + len <= I2C_PAGE_SIZE)
208162306a36Sopenharmony_ci		return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan,
208262306a36Sopenharmony_ci				 I2C_DEV_ADDR_A0, offset, len, data);
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	/* offset + len spans 0xa0 and 0xa1 pages */
208562306a36Sopenharmony_ci	if (offset <= I2C_PAGE_SIZE) {
208662306a36Sopenharmony_ci		/* read 0xa0 page */
208762306a36Sopenharmony_ci		len = I2C_PAGE_SIZE - offset;
208862306a36Sopenharmony_ci		ret =  t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan,
208962306a36Sopenharmony_ci				 I2C_DEV_ADDR_A0, offset, len, data);
209062306a36Sopenharmony_ci		if (ret)
209162306a36Sopenharmony_ci			return ret;
209262306a36Sopenharmony_ci		offset = I2C_PAGE_SIZE;
209362306a36Sopenharmony_ci		/* Remaining bytes to be read from second page =
209462306a36Sopenharmony_ci		 * Total length - bytes read from first page
209562306a36Sopenharmony_ci		 */
209662306a36Sopenharmony_ci		len = eprom->len - len;
209762306a36Sopenharmony_ci	}
209862306a36Sopenharmony_ci	/* Read additional optical diagnostics from page 0xa2 if supported */
209962306a36Sopenharmony_ci	return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, I2C_DEV_ADDR_A2,
210062306a36Sopenharmony_ci			 offset, len, &data[eprom->len - len]);
210162306a36Sopenharmony_ci}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_cistatic u32 cxgb4_get_priv_flags(struct net_device *netdev)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
210662306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	return (adapter->eth_flags | pi->eth_flags);
210962306a36Sopenharmony_ci}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci/**
211262306a36Sopenharmony_ci *	set_flags - set/unset specified flags if passed in new_flags
211362306a36Sopenharmony_ci *	@cur_flags: pointer to current flags
211462306a36Sopenharmony_ci *	@new_flags: new incoming flags
211562306a36Sopenharmony_ci *	@flags: set of flags to set/unset
211662306a36Sopenharmony_ci */
211762306a36Sopenharmony_cistatic inline void set_flags(u32 *cur_flags, u32 new_flags, u32 flags)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	*cur_flags = (*cur_flags & ~flags) | (new_flags & flags);
212062306a36Sopenharmony_ci}
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_cistatic int cxgb4_set_priv_flags(struct net_device *netdev, u32 flags)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
212562306a36Sopenharmony_ci	struct adapter *adapter = pi->adapter;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	set_flags(&adapter->eth_flags, flags, PRIV_FLAGS_ADAP);
212862306a36Sopenharmony_ci	set_flags(&pi->eth_flags, flags, PRIV_FLAGS_PORT);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	return 0;
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic void cxgb4_lb_test(struct net_device *netdev, u64 *lb_status)
213462306a36Sopenharmony_ci{
213562306a36Sopenharmony_ci	int dev_state = netif_running(netdev);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	if (dev_state) {
213862306a36Sopenharmony_ci		netif_tx_stop_all_queues(netdev);
213962306a36Sopenharmony_ci		netif_carrier_off(netdev);
214062306a36Sopenharmony_ci	}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	*lb_status = cxgb4_selftest_lb_pkt(netdev);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	if (dev_state) {
214562306a36Sopenharmony_ci		netif_tx_start_all_queues(netdev);
214662306a36Sopenharmony_ci		netif_carrier_on(netdev);
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_cistatic void cxgb4_self_test(struct net_device *netdev,
215162306a36Sopenharmony_ci			    struct ethtool_test *eth_test, u64 *data)
215262306a36Sopenharmony_ci{
215362306a36Sopenharmony_ci	struct port_info *pi = netdev_priv(netdev);
215462306a36Sopenharmony_ci	struct adapter *adap = pi->adapter;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	memset(data, 0, sizeof(u64) * CXGB4_ETHTOOL_MAX_TEST);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	if (!(adap->flags & CXGB4_FULL_INIT_DONE) ||
215962306a36Sopenharmony_ci	    !(adap->flags & CXGB4_FW_OK)) {
216062306a36Sopenharmony_ci		eth_test->flags |= ETH_TEST_FL_FAILED;
216162306a36Sopenharmony_ci		return;
216262306a36Sopenharmony_ci	}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	if (eth_test->flags & ETH_TEST_FL_OFFLINE)
216562306a36Sopenharmony_ci		cxgb4_lb_test(netdev, &data[CXGB4_ETHTOOL_LB_TEST]);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	if (data[CXGB4_ETHTOOL_LB_TEST])
216862306a36Sopenharmony_ci		eth_test->flags |= ETH_TEST_FL_FAILED;
216962306a36Sopenharmony_ci}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_cistatic const struct ethtool_ops cxgb_ethtool_ops = {
217262306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
217362306a36Sopenharmony_ci				     ETHTOOL_COALESCE_RX_MAX_FRAMES |
217462306a36Sopenharmony_ci				     ETHTOOL_COALESCE_TX_USECS_IRQ |
217562306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
217662306a36Sopenharmony_ci	.get_link_ksettings = get_link_ksettings,
217762306a36Sopenharmony_ci	.set_link_ksettings = set_link_ksettings,
217862306a36Sopenharmony_ci	.get_fecparam      = get_fecparam,
217962306a36Sopenharmony_ci	.set_fecparam      = set_fecparam,
218062306a36Sopenharmony_ci	.get_drvinfo       = get_drvinfo,
218162306a36Sopenharmony_ci	.get_msglevel      = get_msglevel,
218262306a36Sopenharmony_ci	.set_msglevel      = set_msglevel,
218362306a36Sopenharmony_ci	.get_ringparam     = get_sge_param,
218462306a36Sopenharmony_ci	.set_ringparam     = set_sge_param,
218562306a36Sopenharmony_ci	.get_coalesce      = get_coalesce,
218662306a36Sopenharmony_ci	.set_coalesce      = set_coalesce,
218762306a36Sopenharmony_ci	.get_eeprom_len    = get_eeprom_len,
218862306a36Sopenharmony_ci	.get_eeprom        = get_eeprom,
218962306a36Sopenharmony_ci	.set_eeprom        = set_eeprom,
219062306a36Sopenharmony_ci	.get_pauseparam    = get_pauseparam,
219162306a36Sopenharmony_ci	.set_pauseparam    = set_pauseparam,
219262306a36Sopenharmony_ci	.get_link          = ethtool_op_get_link,
219362306a36Sopenharmony_ci	.get_strings       = get_strings,
219462306a36Sopenharmony_ci	.set_phys_id       = identify_port,
219562306a36Sopenharmony_ci	.nway_reset        = restart_autoneg,
219662306a36Sopenharmony_ci	.get_sset_count    = get_sset_count,
219762306a36Sopenharmony_ci	.get_ethtool_stats = get_stats,
219862306a36Sopenharmony_ci	.get_regs_len      = get_regs_len,
219962306a36Sopenharmony_ci	.get_regs          = get_regs,
220062306a36Sopenharmony_ci	.get_rxnfc         = get_rxnfc,
220162306a36Sopenharmony_ci	.set_rxnfc         = set_rxnfc,
220262306a36Sopenharmony_ci	.get_rxfh_indir_size = get_rss_table_size,
220362306a36Sopenharmony_ci	.get_rxfh	   = get_rss_table,
220462306a36Sopenharmony_ci	.set_rxfh	   = set_rss_table,
220562306a36Sopenharmony_ci	.self_test	   = cxgb4_self_test,
220662306a36Sopenharmony_ci	.flash_device      = set_flash,
220762306a36Sopenharmony_ci	.get_ts_info       = get_ts_info,
220862306a36Sopenharmony_ci	.set_dump          = set_dump,
220962306a36Sopenharmony_ci	.get_dump_flag     = get_dump_flag,
221062306a36Sopenharmony_ci	.get_dump_data     = get_dump_data,
221162306a36Sopenharmony_ci	.get_module_info   = cxgb4_get_module_info,
221262306a36Sopenharmony_ci	.get_module_eeprom = cxgb4_get_module_eeprom,
221362306a36Sopenharmony_ci	.get_priv_flags    = cxgb4_get_priv_flags,
221462306a36Sopenharmony_ci	.set_priv_flags    = cxgb4_set_priv_flags,
221562306a36Sopenharmony_ci};
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_civoid cxgb4_cleanup_ethtool_filters(struct adapter *adap)
221862306a36Sopenharmony_ci{
221962306a36Sopenharmony_ci	struct cxgb4_ethtool_filter_info *eth_filter_info;
222062306a36Sopenharmony_ci	u8 i;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (!adap->ethtool_filters)
222362306a36Sopenharmony_ci		return;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	eth_filter_info = adap->ethtool_filters->port;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	if (eth_filter_info) {
222862306a36Sopenharmony_ci		for (i = 0; i < adap->params.nports; i++) {
222962306a36Sopenharmony_ci			kvfree(eth_filter_info[i].loc_array);
223062306a36Sopenharmony_ci			bitmap_free(eth_filter_info[i].bmap);
223162306a36Sopenharmony_ci		}
223262306a36Sopenharmony_ci		kfree(eth_filter_info);
223362306a36Sopenharmony_ci	}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	kfree(adap->ethtool_filters);
223662306a36Sopenharmony_ci}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ciint cxgb4_init_ethtool_filters(struct adapter *adap)
223962306a36Sopenharmony_ci{
224062306a36Sopenharmony_ci	struct cxgb4_ethtool_filter_info *eth_filter_info;
224162306a36Sopenharmony_ci	struct cxgb4_ethtool_filter *eth_filter;
224262306a36Sopenharmony_ci	struct tid_info *tids = &adap->tids;
224362306a36Sopenharmony_ci	u32 nentries, i;
224462306a36Sopenharmony_ci	int ret;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	eth_filter = kzalloc(sizeof(*eth_filter), GFP_KERNEL);
224762306a36Sopenharmony_ci	if (!eth_filter)
224862306a36Sopenharmony_ci		return -ENOMEM;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	eth_filter_info = kcalloc(adap->params.nports,
225162306a36Sopenharmony_ci				  sizeof(*eth_filter_info),
225262306a36Sopenharmony_ci				  GFP_KERNEL);
225362306a36Sopenharmony_ci	if (!eth_filter_info) {
225462306a36Sopenharmony_ci		ret = -ENOMEM;
225562306a36Sopenharmony_ci		goto free_eth_filter;
225662306a36Sopenharmony_ci	}
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	eth_filter->port = eth_filter_info;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	nentries = tids->nhpftids + tids->nftids;
226162306a36Sopenharmony_ci	if (is_hashfilter(adap))
226262306a36Sopenharmony_ci		nentries += tids->nhash +
226362306a36Sopenharmony_ci			    (adap->tids.stid_base - adap->tids.tid_base);
226462306a36Sopenharmony_ci	eth_filter->nentries = nentries;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	for (i = 0; i < adap->params.nports; i++) {
226762306a36Sopenharmony_ci		eth_filter->port[i].loc_array = kvzalloc(nentries, GFP_KERNEL);
226862306a36Sopenharmony_ci		if (!eth_filter->port[i].loc_array) {
226962306a36Sopenharmony_ci			ret = -ENOMEM;
227062306a36Sopenharmony_ci			goto free_eth_finfo;
227162306a36Sopenharmony_ci		}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci		eth_filter->port[i].bmap = bitmap_zalloc(nentries, GFP_KERNEL);
227462306a36Sopenharmony_ci		if (!eth_filter->port[i].bmap) {
227562306a36Sopenharmony_ci			ret = -ENOMEM;
227662306a36Sopenharmony_ci			goto free_eth_finfo;
227762306a36Sopenharmony_ci		}
227862306a36Sopenharmony_ci	}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	adap->ethtool_filters = eth_filter;
228162306a36Sopenharmony_ci	return 0;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_cifree_eth_finfo:
228462306a36Sopenharmony_ci	while (i-- > 0) {
228562306a36Sopenharmony_ci		bitmap_free(eth_filter->port[i].bmap);
228662306a36Sopenharmony_ci		kvfree(eth_filter->port[i].loc_array);
228762306a36Sopenharmony_ci	}
228862306a36Sopenharmony_ci	kfree(eth_filter_info);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_cifree_eth_filter:
229162306a36Sopenharmony_ci	kfree(eth_filter);
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	return ret;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_civoid cxgb4_set_ethtool_ops(struct net_device *netdev)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	netdev->ethtool_ops = &cxgb_ethtool_ops;
229962306a36Sopenharmony_ci}
2300