18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2005 - 2016 Broadcom
48c2ecf20Sopenharmony_ci * All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Contact Information:
78c2ecf20Sopenharmony_ci * linux-drivers@emulex.com
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Emulex
108c2ecf20Sopenharmony_ci * 3333 Susan Street
118c2ecf20Sopenharmony_ci * Costa Mesa, CA 92626
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "be.h"
158c2ecf20Sopenharmony_ci#include "be_cmds.h"
168c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct be_ethtool_stat {
198c2ecf20Sopenharmony_ci	char desc[ETH_GSTRING_LEN];
208c2ecf20Sopenharmony_ci	int type;
218c2ecf20Sopenharmony_ci	int size;
228c2ecf20Sopenharmony_ci	int offset;
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cienum {DRVSTAT_TX, DRVSTAT_RX, DRVSTAT};
268c2ecf20Sopenharmony_ci#define FIELDINFO(_struct, field) sizeof_field(_struct, field), \
278c2ecf20Sopenharmony_ci					offsetof(_struct, field)
288c2ecf20Sopenharmony_ci#define DRVSTAT_TX_INFO(field)	#field, DRVSTAT_TX,\
298c2ecf20Sopenharmony_ci					FIELDINFO(struct be_tx_stats, field)
308c2ecf20Sopenharmony_ci#define DRVSTAT_RX_INFO(field)	#field, DRVSTAT_RX,\
318c2ecf20Sopenharmony_ci					FIELDINFO(struct be_rx_stats, field)
328c2ecf20Sopenharmony_ci#define	DRVSTAT_INFO(field)	#field, DRVSTAT,\
338c2ecf20Sopenharmony_ci					FIELDINFO(struct be_drv_stats, field)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic const struct be_ethtool_stat et_stats[] = {
368c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_crc_errors)},
378c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_alignment_symbol_errors)},
388c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_pause_frames)},
398c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_control_frames)},
408c2ecf20Sopenharmony_ci	/* Received packets dropped when the Ethernet length field
418c2ecf20Sopenharmony_ci	 * is not equal to the actual Ethernet data length.
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_in_range_errors)},
448c2ecf20Sopenharmony_ci	/* Received packets dropped when their length field is >= 1501 bytes
458c2ecf20Sopenharmony_ci	 * and <= 1535 bytes.
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_out_range_errors)},
488c2ecf20Sopenharmony_ci	/* Received packets dropped when they are longer than 9216 bytes */
498c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_frame_too_long)},
508c2ecf20Sopenharmony_ci	/* Received packets dropped when they don't pass the unicast or
518c2ecf20Sopenharmony_ci	 * multicast address filtering.
528c2ecf20Sopenharmony_ci	 */
538c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_address_filtered)},
548c2ecf20Sopenharmony_ci	/* Received packets dropped when IP packet length field is less than
558c2ecf20Sopenharmony_ci	 * the IP header length field.
568c2ecf20Sopenharmony_ci	 */
578c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_dropped_too_small)},
588c2ecf20Sopenharmony_ci	/* Received packets dropped when IP length field is greater than
598c2ecf20Sopenharmony_ci	 * the actual packet length.
608c2ecf20Sopenharmony_ci	 */
618c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_dropped_too_short)},
628c2ecf20Sopenharmony_ci	/* Received packets dropped when the IP header length field is less
638c2ecf20Sopenharmony_ci	 * than 5.
648c2ecf20Sopenharmony_ci	 */
658c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_dropped_header_too_small)},
668c2ecf20Sopenharmony_ci	/* Received packets dropped when the TCP header length field is less
678c2ecf20Sopenharmony_ci	 * than 5 or the TCP header length + IP header length is more
688c2ecf20Sopenharmony_ci	 * than IP packet length.
698c2ecf20Sopenharmony_ci	 */
708c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_dropped_tcp_length)},
718c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_dropped_runt)},
728c2ecf20Sopenharmony_ci	/* Number of received packets dropped when a fifo for descriptors going
738c2ecf20Sopenharmony_ci	 * into the packet demux block overflows. In normal operation, this
748c2ecf20Sopenharmony_ci	 * fifo must never overflow.
758c2ecf20Sopenharmony_ci	 */
768c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rxpp_fifo_overflow_drop)},
778c2ecf20Sopenharmony_ci	/* Received packets dropped when the RX block runs out of space in
788c2ecf20Sopenharmony_ci	 * one of its input FIFOs. This could happen due a long burst of
798c2ecf20Sopenharmony_ci	 * minimum-sized (64b) frames in the receive path.
808c2ecf20Sopenharmony_ci	 * This counter may also be erroneously incremented rarely.
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_input_fifo_overflow_drop)},
838c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_ip_checksum_errs)},
848c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_tcp_checksum_errs)},
858c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_udp_checksum_errs)},
868c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(tx_pauseframes)},
878c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(tx_controlframes)},
888c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_priority_pause_frames)},
898c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(tx_priority_pauseframes)},
908c2ecf20Sopenharmony_ci	/* Received packets dropped when an internal fifo going into
918c2ecf20Sopenharmony_ci	 * main packet buffer tank (PMEM) overflows.
928c2ecf20Sopenharmony_ci	 */
938c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(pmem_fifo_overflow_drop)},
948c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(jabber_events)},
958c2ecf20Sopenharmony_ci	/* Received packets dropped due to lack of available HW packet buffers
968c2ecf20Sopenharmony_ci	 * used to temporarily hold the received packets.
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_drops_no_pbuf)},
998c2ecf20Sopenharmony_ci	/* Received packets dropped due to input receive buffer
1008c2ecf20Sopenharmony_ci	 * descriptor fifo overflowing.
1018c2ecf20Sopenharmony_ci	 */
1028c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_drops_no_erx_descr)},
1038c2ecf20Sopenharmony_ci	/* Packets dropped because the internal FIFO to the offloaded TCP
1048c2ecf20Sopenharmony_ci	 * receive processing block is full. This could happen only for
1058c2ecf20Sopenharmony_ci	 * offloaded iSCSI or FCoE trarffic.
1068c2ecf20Sopenharmony_ci	 */
1078c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_drops_no_tpre_descr)},
1088c2ecf20Sopenharmony_ci	/* Received packets dropped when they need more than 8
1098c2ecf20Sopenharmony_ci	 * receive buffers. This cannot happen as the driver configures
1108c2ecf20Sopenharmony_ci	 * 2048 byte receive buffers.
1118c2ecf20Sopenharmony_ci	 */
1128c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_drops_too_many_frags)},
1138c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(forwarded_packets)},
1148c2ecf20Sopenharmony_ci	/* Received packets dropped when the frame length
1158c2ecf20Sopenharmony_ci	 * is more than 9018 bytes
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_drops_mtu)},
1188c2ecf20Sopenharmony_ci	/* Number of dma mapping errors */
1198c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(dma_map_errors)},
1208c2ecf20Sopenharmony_ci	/* Number of packets dropped due to random early drop function */
1218c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(eth_red_drops)},
1228c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_roce_bytes_lsd)},
1238c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_roce_bytes_msd)},
1248c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(rx_roce_frames)},
1258c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(roce_drops_payload_len)},
1268c2ecf20Sopenharmony_ci	{DRVSTAT_INFO(roce_drops_crc)}
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/* Stats related to multi RX queues: get_stats routine assumes bytes, pkts
1328c2ecf20Sopenharmony_ci * are first and second members respectively.
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cistatic const struct be_ethtool_stat et_rx_stats[] = {
1358c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */
1368c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */
1378c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_vxlan_offload_pkts)},
1388c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_compl)},
1398c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_compl_err)},
1408c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_mcast_pkts)},
1418c2ecf20Sopenharmony_ci	/* Number of page allocation failures while posting receive buffers
1428c2ecf20Sopenharmony_ci	 * to HW.
1438c2ecf20Sopenharmony_ci	 */
1448c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_post_fail)},
1458c2ecf20Sopenharmony_ci	/* Recevied packets dropped due to skb allocation failure */
1468c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_drops_no_skbs)},
1478c2ecf20Sopenharmony_ci	/* Received packets dropped due to lack of available fetched buffers
1488c2ecf20Sopenharmony_ci	 * posted by the driver.
1498c2ecf20Sopenharmony_ci	 */
1508c2ecf20Sopenharmony_ci	{DRVSTAT_RX_INFO(rx_drops_no_frags)}
1518c2ecf20Sopenharmony_ci};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* Stats related to multi TX queues: get_stats routine assumes compl is the
1568c2ecf20Sopenharmony_ci * first member
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_cistatic const struct be_ethtool_stat et_tx_stats[] = {
1598c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */
1608c2ecf20Sopenharmony_ci	/* This counter is incremented when the HW encounters an error while
1618c2ecf20Sopenharmony_ci	 * parsing the packet header of an outgoing TX request. This counter is
1628c2ecf20Sopenharmony_ci	 * applicable only for BE2, BE3 and Skyhawk based adapters.
1638c2ecf20Sopenharmony_ci	 */
1648c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_hdr_parse_err)},
1658c2ecf20Sopenharmony_ci	/* This counter is incremented when an error occurs in the DMA
1668c2ecf20Sopenharmony_ci	 * operation associated with the TX request from the host to the device.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_dma_err)},
1698c2ecf20Sopenharmony_ci	/* This counter is incremented when MAC or VLAN spoof checking is
1708c2ecf20Sopenharmony_ci	 * enabled on the interface and the TX request fails the spoof check
1718c2ecf20Sopenharmony_ci	 * in HW.
1728c2ecf20Sopenharmony_ci	 */
1738c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_spoof_check_err)},
1748c2ecf20Sopenharmony_ci	/* This counter is incremented when the HW encounters an error while
1758c2ecf20Sopenharmony_ci	 * performing TSO offload. This counter is applicable only for Lancer
1768c2ecf20Sopenharmony_ci	 * adapters.
1778c2ecf20Sopenharmony_ci	 */
1788c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_tso_err)},
1798c2ecf20Sopenharmony_ci	/* This counter is incremented when the HW detects Q-in-Q style VLAN
1808c2ecf20Sopenharmony_ci	 * tagging in a packet and such tagging is not expected on the outgoing
1818c2ecf20Sopenharmony_ci	 * interface. This counter is applicable only for Lancer adapters.
1828c2ecf20Sopenharmony_ci	 */
1838c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_qinq_err)},
1848c2ecf20Sopenharmony_ci	/* This counter is incremented when the HW detects parity errors in the
1858c2ecf20Sopenharmony_ci	 * packet data. This counter is applicable only for Lancer adapters.
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_internal_parity_err)},
1888c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_sge_err)},
1898c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_bytes)},
1908c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_pkts)},
1918c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_vxlan_offload_pkts)},
1928c2ecf20Sopenharmony_ci	/* Number of skbs queued for trasmission by the driver */
1938c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_reqs)},
1948c2ecf20Sopenharmony_ci	/* Number of times the TX queue was stopped due to lack
1958c2ecf20Sopenharmony_ci	 * of spaces in the TXQ.
1968c2ecf20Sopenharmony_ci	 */
1978c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_stops)},
1988c2ecf20Sopenharmony_ci	/* Pkts dropped in the driver's transmit path */
1998c2ecf20Sopenharmony_ci	{DRVSTAT_TX_INFO(tx_drv_drops)}
2008c2ecf20Sopenharmony_ci};
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats))
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic const char et_self_tests[][ETH_GSTRING_LEN] = {
2058c2ecf20Sopenharmony_ci	"MAC Loopback test",
2068c2ecf20Sopenharmony_ci	"PHY Loopback test",
2078c2ecf20Sopenharmony_ci	"External Loopback test",
2088c2ecf20Sopenharmony_ci	"DDR DMA test",
2098c2ecf20Sopenharmony_ci	"Link test"
2108c2ecf20Sopenharmony_ci};
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
2138c2ecf20Sopenharmony_ci#define BE_MAC_LOOPBACK 0x0
2148c2ecf20Sopenharmony_ci#define BE_PHY_LOOPBACK 0x1
2158c2ecf20Sopenharmony_ci#define BE_ONE_PORT_EXT_LOOPBACK 0x2
2168c2ecf20Sopenharmony_ci#define BE_NO_LOOPBACK 0xff
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic void be_get_drvinfo(struct net_device *netdev,
2198c2ecf20Sopenharmony_ci			   struct ethtool_drvinfo *drvinfo)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
2248c2ecf20Sopenharmony_ci	if (!memcmp(adapter->fw_ver, adapter->fw_on_flash, FW_VER_LEN))
2258c2ecf20Sopenharmony_ci		strlcpy(drvinfo->fw_version, adapter->fw_ver,
2268c2ecf20Sopenharmony_ci			sizeof(drvinfo->fw_version));
2278c2ecf20Sopenharmony_ci	else
2288c2ecf20Sopenharmony_ci		snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
2298c2ecf20Sopenharmony_ci			 "%s [%s]", adapter->fw_ver, adapter->fw_on_flash);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
2328c2ecf20Sopenharmony_ci		sizeof(drvinfo->bus_info));
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic u32 lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	u32 data_read = 0, eof;
2388c2ecf20Sopenharmony_ci	u8 addn_status;
2398c2ecf20Sopenharmony_ci	struct be_dma_mem data_len_cmd;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	memset(&data_len_cmd, 0, sizeof(data_len_cmd));
2428c2ecf20Sopenharmony_ci	/* data_offset and data_size should be 0 to get reg len */
2438c2ecf20Sopenharmony_ci	lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0, file_name,
2448c2ecf20Sopenharmony_ci			       &data_read, &eof, &addn_status);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return data_read;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic int be_get_dump_len(struct be_adapter *adapter)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	u32 dump_size = 0;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (lancer_chip(adapter))
2548c2ecf20Sopenharmony_ci		dump_size = lancer_cmd_get_file_len(adapter,
2558c2ecf20Sopenharmony_ci						    LANCER_FW_DUMP_FILE);
2568c2ecf20Sopenharmony_ci	else
2578c2ecf20Sopenharmony_ci		dump_size = adapter->fat_dump_len;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return dump_size;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic int lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,
2638c2ecf20Sopenharmony_ci				u32 buf_len, void *buf)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct be_dma_mem read_cmd;
2668c2ecf20Sopenharmony_ci	u32 read_len = 0, total_read_len = 0, chunk_size;
2678c2ecf20Sopenharmony_ci	u32 eof = 0;
2688c2ecf20Sopenharmony_ci	u8 addn_status;
2698c2ecf20Sopenharmony_ci	int status = 0;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	read_cmd.size = LANCER_READ_FILE_CHUNK;
2728c2ecf20Sopenharmony_ci	read_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, read_cmd.size,
2738c2ecf20Sopenharmony_ci					 &read_cmd.dma, GFP_ATOMIC);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (!read_cmd.va) {
2768c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
2778c2ecf20Sopenharmony_ci			"Memory allocation failure while reading dump\n");
2788c2ecf20Sopenharmony_ci		return -ENOMEM;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	while ((total_read_len < buf_len) && !eof) {
2828c2ecf20Sopenharmony_ci		chunk_size = min_t(u32, (buf_len - total_read_len),
2838c2ecf20Sopenharmony_ci				   LANCER_READ_FILE_CHUNK);
2848c2ecf20Sopenharmony_ci		chunk_size = ALIGN(chunk_size, 4);
2858c2ecf20Sopenharmony_ci		status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size,
2868c2ecf20Sopenharmony_ci						total_read_len, file_name,
2878c2ecf20Sopenharmony_ci						&read_len, &eof, &addn_status);
2888c2ecf20Sopenharmony_ci		if (!status) {
2898c2ecf20Sopenharmony_ci			memcpy(buf + total_read_len, read_cmd.va, read_len);
2908c2ecf20Sopenharmony_ci			total_read_len += read_len;
2918c2ecf20Sopenharmony_ci			eof &= LANCER_READ_FILE_EOF_MASK;
2928c2ecf20Sopenharmony_ci		} else {
2938c2ecf20Sopenharmony_ci			status = -EIO;
2948c2ecf20Sopenharmony_ci			break;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci	dma_free_coherent(&adapter->pdev->dev, read_cmd.size, read_cmd.va,
2988c2ecf20Sopenharmony_ci			  read_cmd.dma);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return status;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int be_read_dump_data(struct be_adapter *adapter, u32 dump_len,
3048c2ecf20Sopenharmony_ci			     void *buf)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	int status = 0;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (lancer_chip(adapter))
3098c2ecf20Sopenharmony_ci		status = lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE,
3108c2ecf20Sopenharmony_ci					      dump_len, buf);
3118c2ecf20Sopenharmony_ci	else
3128c2ecf20Sopenharmony_ci		status = be_cmd_get_fat_dump(adapter, dump_len, buf);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return status;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int be_get_coalesce(struct net_device *netdev,
3188c2ecf20Sopenharmony_ci			   struct ethtool_coalesce *et)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
3218c2ecf20Sopenharmony_ci	struct be_aic_obj *aic = &adapter->aic_obj[0];
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	et->rx_coalesce_usecs = aic->prev_eqd;
3248c2ecf20Sopenharmony_ci	et->rx_coalesce_usecs_high = aic->max_eqd;
3258c2ecf20Sopenharmony_ci	et->rx_coalesce_usecs_low = aic->min_eqd;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	et->tx_coalesce_usecs = aic->prev_eqd;
3288c2ecf20Sopenharmony_ci	et->tx_coalesce_usecs_high = aic->max_eqd;
3298c2ecf20Sopenharmony_ci	et->tx_coalesce_usecs_low = aic->min_eqd;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	et->use_adaptive_rx_coalesce = adapter->aic_enabled;
3328c2ecf20Sopenharmony_ci	et->use_adaptive_tx_coalesce = adapter->aic_enabled;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/* TX attributes are ignored. Only RX attributes are considered
3388c2ecf20Sopenharmony_ci * eqd cmd is issued in the worker thread.
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_cistatic int be_set_coalesce(struct net_device *netdev,
3418c2ecf20Sopenharmony_ci			   struct ethtool_coalesce *et)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
3448c2ecf20Sopenharmony_ci	struct be_aic_obj *aic = &adapter->aic_obj[0];
3458c2ecf20Sopenharmony_ci	struct be_eq_obj *eqo;
3468c2ecf20Sopenharmony_ci	int i;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	adapter->aic_enabled = et->use_adaptive_rx_coalesce;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	for_all_evt_queues(adapter, eqo, i) {
3518c2ecf20Sopenharmony_ci		aic->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD);
3528c2ecf20Sopenharmony_ci		aic->min_eqd = min(et->rx_coalesce_usecs_low, aic->max_eqd);
3538c2ecf20Sopenharmony_ci		aic->et_eqd = min(et->rx_coalesce_usecs, aic->max_eqd);
3548c2ecf20Sopenharmony_ci		aic->et_eqd = max(aic->et_eqd, aic->min_eqd);
3558c2ecf20Sopenharmony_ci		aic++;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* For Skyhawk, the EQD setting happens via EQ_DB when AIC is enabled.
3598c2ecf20Sopenharmony_ci	 * When AIC is disabled, persistently force set EQD value via the
3608c2ecf20Sopenharmony_ci	 * FW cmd, so that we don't have to calculate the delay multiplier
3618c2ecf20Sopenharmony_ci	 * encode value each time EQ_DB is rung
3628c2ecf20Sopenharmony_ci	 */
3638c2ecf20Sopenharmony_ci	if (!et->use_adaptive_rx_coalesce && skyhawk_chip(adapter))
3648c2ecf20Sopenharmony_ci		be_eqd_update(adapter, true);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void be_get_ethtool_stats(struct net_device *netdev,
3708c2ecf20Sopenharmony_ci				 struct ethtool_stats *stats, uint64_t *data)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
3738c2ecf20Sopenharmony_ci	struct be_rx_obj *rxo;
3748c2ecf20Sopenharmony_ci	struct be_tx_obj *txo;
3758c2ecf20Sopenharmony_ci	void *p;
3768c2ecf20Sopenharmony_ci	unsigned int i, j, base = 0, start;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
3798c2ecf20Sopenharmony_ci		p = (u8 *)&adapter->drv_stats + et_stats[i].offset;
3808c2ecf20Sopenharmony_ci		data[i] = *(u32 *)p;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci	base += ETHTOOL_STATS_NUM;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	for_all_rx_queues(adapter, rxo, j) {
3858c2ecf20Sopenharmony_ci		struct be_rx_stats *stats = rx_stats(rxo);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		do {
3888c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&stats->sync);
3898c2ecf20Sopenharmony_ci			data[base] = stats->rx_bytes;
3908c2ecf20Sopenharmony_ci			data[base + 1] = stats->rx_pkts;
3918c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&stats->sync, start));
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
3948c2ecf20Sopenharmony_ci			p = (u8 *)stats + et_rx_stats[i].offset;
3958c2ecf20Sopenharmony_ci			data[base + i] = *(u32 *)p;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci		base += ETHTOOL_RXSTATS_NUM;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	for_all_tx_queues(adapter, txo, j) {
4018c2ecf20Sopenharmony_ci		struct be_tx_stats *stats = tx_stats(txo);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		do {
4048c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&stats->sync_compl);
4058c2ecf20Sopenharmony_ci			data[base] = stats->tx_compl;
4068c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&stats->sync_compl, start));
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci		do {
4098c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&stats->sync);
4108c2ecf20Sopenharmony_ci			for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
4118c2ecf20Sopenharmony_ci				p = (u8 *)stats + et_tx_stats[i].offset;
4128c2ecf20Sopenharmony_ci				data[base + i] =
4138c2ecf20Sopenharmony_ci					(et_tx_stats[i].size == sizeof(u64)) ?
4148c2ecf20Sopenharmony_ci						*(u64 *)p : *(u32 *)p;
4158c2ecf20Sopenharmony_ci			}
4168c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&stats->sync, start));
4178c2ecf20Sopenharmony_ci		base += ETHTOOL_TXSTATS_NUM;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic const char be_priv_flags[][ETH_GSTRING_LEN] = {
4228c2ecf20Sopenharmony_ci	"disable-tpe-recovery"
4238c2ecf20Sopenharmony_ci};
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic void be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
4268c2ecf20Sopenharmony_ci				uint8_t *data)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
4298c2ecf20Sopenharmony_ci	int i, j;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	switch (stringset) {
4328c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
4338c2ecf20Sopenharmony_ci		for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
4348c2ecf20Sopenharmony_ci			memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
4358c2ecf20Sopenharmony_ci			data += ETH_GSTRING_LEN;
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_rx_qs; i++) {
4388c2ecf20Sopenharmony_ci			for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) {
4398c2ecf20Sopenharmony_ci				sprintf(data, "rxq%d: %s", i,
4408c2ecf20Sopenharmony_ci					et_rx_stats[j].desc);
4418c2ecf20Sopenharmony_ci				data += ETH_GSTRING_LEN;
4428c2ecf20Sopenharmony_ci			}
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci		for (i = 0; i < adapter->num_tx_qs; i++) {
4458c2ecf20Sopenharmony_ci			for (j = 0; j < ETHTOOL_TXSTATS_NUM; j++) {
4468c2ecf20Sopenharmony_ci				sprintf(data, "txq%d: %s", i,
4478c2ecf20Sopenharmony_ci					et_tx_stats[j].desc);
4488c2ecf20Sopenharmony_ci				data += ETH_GSTRING_LEN;
4498c2ecf20Sopenharmony_ci			}
4508c2ecf20Sopenharmony_ci		}
4518c2ecf20Sopenharmony_ci		break;
4528c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
4538c2ecf20Sopenharmony_ci		for (i = 0; i < ETHTOOL_TESTS_NUM; i++) {
4548c2ecf20Sopenharmony_ci			memcpy(data, et_self_tests[i], ETH_GSTRING_LEN);
4558c2ecf20Sopenharmony_ci			data += ETH_GSTRING_LEN;
4568c2ecf20Sopenharmony_ci		}
4578c2ecf20Sopenharmony_ci		break;
4588c2ecf20Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
4598c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(be_priv_flags); i++)
4608c2ecf20Sopenharmony_ci			strcpy(data + i * ETH_GSTRING_LEN, be_priv_flags[i]);
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int be_get_sset_count(struct net_device *netdev, int stringset)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	switch (stringset) {
4708c2ecf20Sopenharmony_ci	case ETH_SS_TEST:
4718c2ecf20Sopenharmony_ci		return ETHTOOL_TESTS_NUM;
4728c2ecf20Sopenharmony_ci	case ETH_SS_STATS:
4738c2ecf20Sopenharmony_ci		return ETHTOOL_STATS_NUM +
4748c2ecf20Sopenharmony_ci			adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM +
4758c2ecf20Sopenharmony_ci			adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM;
4768c2ecf20Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
4778c2ecf20Sopenharmony_ci		return ARRAY_SIZE(be_priv_flags);
4788c2ecf20Sopenharmony_ci	default:
4798c2ecf20Sopenharmony_ci		return -EINVAL;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic u32 be_get_port_type(struct be_adapter *adapter)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	u32 port;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	switch (adapter->phy.interface_type) {
4888c2ecf20Sopenharmony_ci	case PHY_TYPE_BASET_1GB:
4898c2ecf20Sopenharmony_ci	case PHY_TYPE_BASEX_1GB:
4908c2ecf20Sopenharmony_ci	case PHY_TYPE_SGMII:
4918c2ecf20Sopenharmony_ci		port = PORT_TP;
4928c2ecf20Sopenharmony_ci		break;
4938c2ecf20Sopenharmony_ci	case PHY_TYPE_SFP_PLUS_10GB:
4948c2ecf20Sopenharmony_ci		if (adapter->phy.cable_type & SFP_PLUS_COPPER_CABLE)
4958c2ecf20Sopenharmony_ci			port = PORT_DA;
4968c2ecf20Sopenharmony_ci		else
4978c2ecf20Sopenharmony_ci			port = PORT_FIBRE;
4988c2ecf20Sopenharmony_ci		break;
4998c2ecf20Sopenharmony_ci	case PHY_TYPE_QSFP:
5008c2ecf20Sopenharmony_ci		if (adapter->phy.cable_type & QSFP_PLUS_CR4_CABLE)
5018c2ecf20Sopenharmony_ci			port = PORT_DA;
5028c2ecf20Sopenharmony_ci		else
5038c2ecf20Sopenharmony_ci			port = PORT_FIBRE;
5048c2ecf20Sopenharmony_ci		break;
5058c2ecf20Sopenharmony_ci	case PHY_TYPE_XFP_10GB:
5068c2ecf20Sopenharmony_ci	case PHY_TYPE_SFP_1GB:
5078c2ecf20Sopenharmony_ci		port = PORT_FIBRE;
5088c2ecf20Sopenharmony_ci		break;
5098c2ecf20Sopenharmony_ci	case PHY_TYPE_BASET_10GB:
5108c2ecf20Sopenharmony_ci		port = PORT_TP;
5118c2ecf20Sopenharmony_ci		break;
5128c2ecf20Sopenharmony_ci	default:
5138c2ecf20Sopenharmony_ci		port = PORT_OTHER;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return port;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic u32 convert_to_et_setting(struct be_adapter *adapter, u32 if_speeds)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	u32 val = 0;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	switch (adapter->phy.interface_type) {
5248c2ecf20Sopenharmony_ci	case PHY_TYPE_BASET_1GB:
5258c2ecf20Sopenharmony_ci	case PHY_TYPE_BASEX_1GB:
5268c2ecf20Sopenharmony_ci	case PHY_TYPE_SGMII:
5278c2ecf20Sopenharmony_ci		val |= SUPPORTED_TP;
5288c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_1GBPS)
5298c2ecf20Sopenharmony_ci			val |= SUPPORTED_1000baseT_Full;
5308c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_100MBPS)
5318c2ecf20Sopenharmony_ci			val |= SUPPORTED_100baseT_Full;
5328c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_10MBPS)
5338c2ecf20Sopenharmony_ci			val |= SUPPORTED_10baseT_Full;
5348c2ecf20Sopenharmony_ci		break;
5358c2ecf20Sopenharmony_ci	case PHY_TYPE_KX4_10GB:
5368c2ecf20Sopenharmony_ci		val |= SUPPORTED_Backplane;
5378c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_1GBPS)
5388c2ecf20Sopenharmony_ci			val |= SUPPORTED_1000baseKX_Full;
5398c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_10GBPS)
5408c2ecf20Sopenharmony_ci			val |= SUPPORTED_10000baseKX4_Full;
5418c2ecf20Sopenharmony_ci		break;
5428c2ecf20Sopenharmony_ci	case PHY_TYPE_KR2_20GB:
5438c2ecf20Sopenharmony_ci		val |= SUPPORTED_Backplane;
5448c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_10GBPS)
5458c2ecf20Sopenharmony_ci			val |= SUPPORTED_10000baseKR_Full;
5468c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_20GBPS)
5478c2ecf20Sopenharmony_ci			val |= SUPPORTED_20000baseKR2_Full;
5488c2ecf20Sopenharmony_ci		break;
5498c2ecf20Sopenharmony_ci	case PHY_TYPE_KR_10GB:
5508c2ecf20Sopenharmony_ci		val |= SUPPORTED_Backplane |
5518c2ecf20Sopenharmony_ci				SUPPORTED_10000baseKR_Full;
5528c2ecf20Sopenharmony_ci		break;
5538c2ecf20Sopenharmony_ci	case PHY_TYPE_KR4_40GB:
5548c2ecf20Sopenharmony_ci		val |= SUPPORTED_Backplane;
5558c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_10GBPS)
5568c2ecf20Sopenharmony_ci			val |= SUPPORTED_10000baseKR_Full;
5578c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_40GBPS)
5588c2ecf20Sopenharmony_ci			val |= SUPPORTED_40000baseKR4_Full;
5598c2ecf20Sopenharmony_ci		break;
5608c2ecf20Sopenharmony_ci	case PHY_TYPE_QSFP:
5618c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_40GBPS) {
5628c2ecf20Sopenharmony_ci			switch (adapter->phy.cable_type) {
5638c2ecf20Sopenharmony_ci			case QSFP_PLUS_CR4_CABLE:
5648c2ecf20Sopenharmony_ci				val |= SUPPORTED_40000baseCR4_Full;
5658c2ecf20Sopenharmony_ci				break;
5668c2ecf20Sopenharmony_ci			case QSFP_PLUS_LR4_CABLE:
5678c2ecf20Sopenharmony_ci				val |= SUPPORTED_40000baseLR4_Full;
5688c2ecf20Sopenharmony_ci				break;
5698c2ecf20Sopenharmony_ci			default:
5708c2ecf20Sopenharmony_ci				val |= SUPPORTED_40000baseSR4_Full;
5718c2ecf20Sopenharmony_ci				break;
5728c2ecf20Sopenharmony_ci			}
5738c2ecf20Sopenharmony_ci		}
5748c2ecf20Sopenharmony_ci		fallthrough;
5758c2ecf20Sopenharmony_ci	case PHY_TYPE_SFP_PLUS_10GB:
5768c2ecf20Sopenharmony_ci	case PHY_TYPE_XFP_10GB:
5778c2ecf20Sopenharmony_ci	case PHY_TYPE_SFP_1GB:
5788c2ecf20Sopenharmony_ci		val |= SUPPORTED_FIBRE;
5798c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_10GBPS)
5808c2ecf20Sopenharmony_ci			val |= SUPPORTED_10000baseT_Full;
5818c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_1GBPS)
5828c2ecf20Sopenharmony_ci			val |= SUPPORTED_1000baseT_Full;
5838c2ecf20Sopenharmony_ci		break;
5848c2ecf20Sopenharmony_ci	case PHY_TYPE_BASET_10GB:
5858c2ecf20Sopenharmony_ci		val |= SUPPORTED_TP;
5868c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_10GBPS)
5878c2ecf20Sopenharmony_ci			val |= SUPPORTED_10000baseT_Full;
5888c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_1GBPS)
5898c2ecf20Sopenharmony_ci			val |= SUPPORTED_1000baseT_Full;
5908c2ecf20Sopenharmony_ci		if (if_speeds & BE_SUPPORTED_SPEED_100MBPS)
5918c2ecf20Sopenharmony_ci			val |= SUPPORTED_100baseT_Full;
5928c2ecf20Sopenharmony_ci		break;
5938c2ecf20Sopenharmony_ci	default:
5948c2ecf20Sopenharmony_ci		val |= SUPPORTED_TP;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return val;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cibool be_pause_supported(struct be_adapter *adapter)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	return (adapter->phy.interface_type == PHY_TYPE_SFP_PLUS_10GB ||
6038c2ecf20Sopenharmony_ci		adapter->phy.interface_type == PHY_TYPE_XFP_10GB) ?
6048c2ecf20Sopenharmony_ci		false : true;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int be_get_link_ksettings(struct net_device *netdev,
6088c2ecf20Sopenharmony_ci				 struct ethtool_link_ksettings *cmd)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
6118c2ecf20Sopenharmony_ci	u8 link_status;
6128c2ecf20Sopenharmony_ci	u16 link_speed = 0;
6138c2ecf20Sopenharmony_ci	int status;
6148c2ecf20Sopenharmony_ci	u32 auto_speeds;
6158c2ecf20Sopenharmony_ci	u32 fixed_speeds;
6168c2ecf20Sopenharmony_ci	u32 supported = 0, advertising = 0;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (adapter->phy.link_speed < 0) {
6198c2ecf20Sopenharmony_ci		status = be_cmd_link_status_query(adapter, &link_speed,
6208c2ecf20Sopenharmony_ci						  &link_status, 0);
6218c2ecf20Sopenharmony_ci		if (!status)
6228c2ecf20Sopenharmony_ci			be_link_status_update(adapter, link_status);
6238c2ecf20Sopenharmony_ci		cmd->base.speed = link_speed;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		status = be_cmd_get_phy_info(adapter);
6268c2ecf20Sopenharmony_ci		if (!status) {
6278c2ecf20Sopenharmony_ci			auto_speeds = adapter->phy.auto_speeds_supported;
6288c2ecf20Sopenharmony_ci			fixed_speeds = adapter->phy.fixed_speeds_supported;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci			be_cmd_query_cable_type(adapter);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci			supported =
6338c2ecf20Sopenharmony_ci				convert_to_et_setting(adapter,
6348c2ecf20Sopenharmony_ci						      auto_speeds |
6358c2ecf20Sopenharmony_ci						      fixed_speeds);
6368c2ecf20Sopenharmony_ci			advertising =
6378c2ecf20Sopenharmony_ci				convert_to_et_setting(adapter, auto_speeds);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci			cmd->base.port = be_get_port_type(adapter);
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci			if (adapter->phy.auto_speeds_supported) {
6428c2ecf20Sopenharmony_ci				supported |= SUPPORTED_Autoneg;
6438c2ecf20Sopenharmony_ci				cmd->base.autoneg = AUTONEG_ENABLE;
6448c2ecf20Sopenharmony_ci				advertising |= ADVERTISED_Autoneg;
6458c2ecf20Sopenharmony_ci			}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci			supported |= SUPPORTED_Pause;
6488c2ecf20Sopenharmony_ci			if (be_pause_supported(adapter))
6498c2ecf20Sopenharmony_ci				advertising |= ADVERTISED_Pause;
6508c2ecf20Sopenharmony_ci		} else {
6518c2ecf20Sopenharmony_ci			cmd->base.port = PORT_OTHER;
6528c2ecf20Sopenharmony_ci			cmd->base.autoneg = AUTONEG_DISABLE;
6538c2ecf20Sopenharmony_ci		}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		/* Save for future use */
6568c2ecf20Sopenharmony_ci		adapter->phy.link_speed = cmd->base.speed;
6578c2ecf20Sopenharmony_ci		adapter->phy.port_type = cmd->base.port;
6588c2ecf20Sopenharmony_ci		adapter->phy.autoneg = cmd->base.autoneg;
6598c2ecf20Sopenharmony_ci		adapter->phy.advertising = advertising;
6608c2ecf20Sopenharmony_ci		adapter->phy.supported = supported;
6618c2ecf20Sopenharmony_ci	} else {
6628c2ecf20Sopenharmony_ci		cmd->base.speed = adapter->phy.link_speed;
6638c2ecf20Sopenharmony_ci		cmd->base.port = adapter->phy.port_type;
6648c2ecf20Sopenharmony_ci		cmd->base.autoneg = adapter->phy.autoneg;
6658c2ecf20Sopenharmony_ci		advertising = adapter->phy.advertising;
6668c2ecf20Sopenharmony_ci		supported = adapter->phy.supported;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	cmd->base.duplex = netif_carrier_ok(netdev) ?
6708c2ecf20Sopenharmony_ci		DUPLEX_FULL : DUPLEX_UNKNOWN;
6718c2ecf20Sopenharmony_ci	cmd->base.phy_address = adapter->port_num;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
6748c2ecf20Sopenharmony_ci						supported);
6758c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
6768c2ecf20Sopenharmony_ci						advertising);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	return 0;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic void be_get_ringparam(struct net_device *netdev,
6828c2ecf20Sopenharmony_ci			     struct ethtool_ringparam *ring)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	ring->rx_max_pending = adapter->rx_obj[0].q.len;
6878c2ecf20Sopenharmony_ci	ring->rx_pending = adapter->rx_obj[0].q.len;
6888c2ecf20Sopenharmony_ci	ring->tx_max_pending = adapter->tx_obj[0].q.len;
6898c2ecf20Sopenharmony_ci	ring->tx_pending = adapter->tx_obj[0].q.len;
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic void
6938c2ecf20Sopenharmony_cibe_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause);
6988c2ecf20Sopenharmony_ci	ecmd->autoneg = adapter->phy.fc_autoneg;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic int
7028c2ecf20Sopenharmony_cibe_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
7058c2ecf20Sopenharmony_ci	int status;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (ecmd->autoneg != adapter->phy.fc_autoneg)
7088c2ecf20Sopenharmony_ci		return -EINVAL;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	status = be_cmd_set_flow_control(adapter, ecmd->tx_pause,
7118c2ecf20Sopenharmony_ci					 ecmd->rx_pause);
7128c2ecf20Sopenharmony_ci	if (status) {
7138c2ecf20Sopenharmony_ci		dev_warn(&adapter->pdev->dev, "Pause param set failed\n");
7148c2ecf20Sopenharmony_ci		return be_cmd_status(status);
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	adapter->tx_fc = ecmd->tx_pause;
7188c2ecf20Sopenharmony_ci	adapter->rx_fc = ecmd->rx_pause;
7198c2ecf20Sopenharmony_ci	return 0;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic int be_set_phys_id(struct net_device *netdev,
7238c2ecf20Sopenharmony_ci			  enum ethtool_phys_id_state state)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
7268c2ecf20Sopenharmony_ci	int status = 0;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	switch (state) {
7298c2ecf20Sopenharmony_ci	case ETHTOOL_ID_ACTIVE:
7308c2ecf20Sopenharmony_ci		status = be_cmd_get_beacon_state(adapter, adapter->hba_port_num,
7318c2ecf20Sopenharmony_ci						 &adapter->beacon_state);
7328c2ecf20Sopenharmony_ci		if (status)
7338c2ecf20Sopenharmony_ci			return be_cmd_status(status);
7348c2ecf20Sopenharmony_ci		return 1;       /* cycle on/off once per second */
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	case ETHTOOL_ID_ON:
7378c2ecf20Sopenharmony_ci		status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num,
7388c2ecf20Sopenharmony_ci						 0, 0, BEACON_STATE_ENABLED);
7398c2ecf20Sopenharmony_ci		break;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	case ETHTOOL_ID_OFF:
7428c2ecf20Sopenharmony_ci		status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num,
7438c2ecf20Sopenharmony_ci						 0, 0, BEACON_STATE_DISABLED);
7448c2ecf20Sopenharmony_ci		break;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	case ETHTOOL_ID_INACTIVE:
7478c2ecf20Sopenharmony_ci		status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num,
7488c2ecf20Sopenharmony_ci						 0, 0, adapter->beacon_state);
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return be_cmd_status(status);
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic int be_set_dump(struct net_device *netdev, struct ethtool_dump *dump)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
7578c2ecf20Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
7588c2ecf20Sopenharmony_ci	int status;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (!lancer_chip(adapter) ||
7618c2ecf20Sopenharmony_ci	    !check_privilege(adapter, MAX_PRIVILEGES))
7628c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	switch (dump->flag) {
7658c2ecf20Sopenharmony_ci	case LANCER_INITIATE_FW_DUMP:
7668c2ecf20Sopenharmony_ci		status = lancer_initiate_dump(adapter);
7678c2ecf20Sopenharmony_ci		if (!status)
7688c2ecf20Sopenharmony_ci			dev_info(dev, "FW dump initiated successfully\n");
7698c2ecf20Sopenharmony_ci		break;
7708c2ecf20Sopenharmony_ci	case LANCER_DELETE_FW_DUMP:
7718c2ecf20Sopenharmony_ci		status = lancer_delete_dump(adapter);
7728c2ecf20Sopenharmony_ci		if (!status)
7738c2ecf20Sopenharmony_ci			dev_info(dev, "FW dump deleted successfully\n");
7748c2ecf20Sopenharmony_ci	break;
7758c2ecf20Sopenharmony_ci	default:
7768c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid dump level: 0x%x\n", dump->flag);
7778c2ecf20Sopenharmony_ci		return -EINVAL;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci	return status;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cistatic void be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (adapter->wol_cap & BE_WOL_CAP) {
7878c2ecf20Sopenharmony_ci		wol->supported |= WAKE_MAGIC;
7888c2ecf20Sopenharmony_ci		if (adapter->wol_en)
7898c2ecf20Sopenharmony_ci			wol->wolopts |= WAKE_MAGIC;
7908c2ecf20Sopenharmony_ci	} else {
7918c2ecf20Sopenharmony_ci		wol->wolopts = 0;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci	memset(&wol->sopass, 0, sizeof(wol->sopass));
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic int be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
7998c2ecf20Sopenharmony_ci	struct device *dev = &adapter->pdev->dev;
8008c2ecf20Sopenharmony_ci	struct be_dma_mem cmd;
8018c2ecf20Sopenharmony_ci	u8 mac[ETH_ALEN];
8028c2ecf20Sopenharmony_ci	bool enable;
8038c2ecf20Sopenharmony_ci	int status;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (wol->wolopts & ~WAKE_MAGIC)
8068c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	if (!(adapter->wol_cap & BE_WOL_CAP)) {
8098c2ecf20Sopenharmony_ci		dev_warn(&adapter->pdev->dev, "WOL not supported\n");
8108c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8118c2ecf20Sopenharmony_ci	}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config);
8148c2ecf20Sopenharmony_ci	cmd.va = dma_alloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL);
8158c2ecf20Sopenharmony_ci	if (!cmd.va)
8168c2ecf20Sopenharmony_ci		return -ENOMEM;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	eth_zero_addr(mac);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	enable = wol->wolopts & WAKE_MAGIC;
8218c2ecf20Sopenharmony_ci	if (enable)
8228c2ecf20Sopenharmony_ci		ether_addr_copy(mac, adapter->netdev->dev_addr);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	status = be_cmd_enable_magic_wol(adapter, mac, &cmd);
8258c2ecf20Sopenharmony_ci	if (status) {
8268c2ecf20Sopenharmony_ci		dev_err(dev, "Could not set Wake-on-lan mac address\n");
8278c2ecf20Sopenharmony_ci		status = be_cmd_status(status);
8288c2ecf20Sopenharmony_ci		goto err;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	pci_enable_wake(adapter->pdev, PCI_D3hot, enable);
8328c2ecf20Sopenharmony_ci	pci_enable_wake(adapter->pdev, PCI_D3cold, enable);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	adapter->wol_en = enable ? true : false;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cierr:
8378c2ecf20Sopenharmony_ci	dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma);
8388c2ecf20Sopenharmony_ci	return status;
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic int be_test_ddr_dma(struct be_adapter *adapter)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	int ret, i;
8448c2ecf20Sopenharmony_ci	struct be_dma_mem ddrdma_cmd;
8458c2ecf20Sopenharmony_ci	static const u64 pattern[2] = {
8468c2ecf20Sopenharmony_ci		0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL
8478c2ecf20Sopenharmony_ci	};
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
8508c2ecf20Sopenharmony_ci	ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev,
8518c2ecf20Sopenharmony_ci					   ddrdma_cmd.size, &ddrdma_cmd.dma,
8528c2ecf20Sopenharmony_ci					   GFP_KERNEL);
8538c2ecf20Sopenharmony_ci	if (!ddrdma_cmd.va)
8548c2ecf20Sopenharmony_ci		return -ENOMEM;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
8578c2ecf20Sopenharmony_ci		ret = be_cmd_ddr_dma_test(adapter, pattern[i],
8588c2ecf20Sopenharmony_ci					  4096, &ddrdma_cmd);
8598c2ecf20Sopenharmony_ci		if (ret != 0)
8608c2ecf20Sopenharmony_ci			goto err;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cierr:
8648c2ecf20Sopenharmony_ci	dma_free_coherent(&adapter->pdev->dev, ddrdma_cmd.size, ddrdma_cmd.va,
8658c2ecf20Sopenharmony_ci			  ddrdma_cmd.dma);
8668c2ecf20Sopenharmony_ci	return be_cmd_status(ret);
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type,
8708c2ecf20Sopenharmony_ci			    u64 *status)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	int ret;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	ret = be_cmd_set_loopback(adapter, adapter->hba_port_num,
8758c2ecf20Sopenharmony_ci				  loopback_type, 1);
8768c2ecf20Sopenharmony_ci	if (ret)
8778c2ecf20Sopenharmony_ci		return ret;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	*status = be_cmd_loopback_test(adapter, adapter->hba_port_num,
8808c2ecf20Sopenharmony_ci				       loopback_type, 1500, 2, 0xabc);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	ret = be_cmd_set_loopback(adapter, adapter->hba_port_num,
8838c2ecf20Sopenharmony_ci				  BE_NO_LOOPBACK, 1);
8848c2ecf20Sopenharmony_ci	if (ret)
8858c2ecf20Sopenharmony_ci		return ret;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	return *status;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic void be_self_test(struct net_device *netdev, struct ethtool_test *test,
8918c2ecf20Sopenharmony_ci			 u64 *data)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
8948c2ecf20Sopenharmony_ci	int status, cnt;
8958c2ecf20Sopenharmony_ci	u8 link_status = 0;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
8988c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Self test not supported\n");
8998c2ecf20Sopenharmony_ci		test->flags |= ETH_TEST_FL_FAILED;
9008c2ecf20Sopenharmony_ci		return;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* check link status before offline tests */
9068c2ecf20Sopenharmony_ci	link_status = netif_carrier_ok(netdev);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (test->flags & ETH_TEST_FL_OFFLINE) {
9098c2ecf20Sopenharmony_ci		if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)
9108c2ecf20Sopenharmony_ci			test->flags |= ETH_TEST_FL_FAILED;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci		if (be_loopback_test(adapter, BE_PHY_LOOPBACK, &data[1]) != 0)
9138c2ecf20Sopenharmony_ci			test->flags |= ETH_TEST_FL_FAILED;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci		if (test->flags & ETH_TEST_FL_EXTERNAL_LB) {
9168c2ecf20Sopenharmony_ci			if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
9178c2ecf20Sopenharmony_ci					     &data[2]) != 0)
9188c2ecf20Sopenharmony_ci				test->flags |= ETH_TEST_FL_FAILED;
9198c2ecf20Sopenharmony_ci			test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
9208c2ecf20Sopenharmony_ci		}
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (!lancer_chip(adapter) && be_test_ddr_dma(adapter) != 0) {
9248c2ecf20Sopenharmony_ci		data[3] = 1;
9258c2ecf20Sopenharmony_ci		test->flags |= ETH_TEST_FL_FAILED;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	/* link status was down prior to test */
9298c2ecf20Sopenharmony_ci	if (!link_status) {
9308c2ecf20Sopenharmony_ci		test->flags |= ETH_TEST_FL_FAILED;
9318c2ecf20Sopenharmony_ci		data[4] = 1;
9328c2ecf20Sopenharmony_ci		return;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	for (cnt = 10; cnt; cnt--) {
9368c2ecf20Sopenharmony_ci		status = be_cmd_link_status_query(adapter, NULL, &link_status,
9378c2ecf20Sopenharmony_ci						  0);
9388c2ecf20Sopenharmony_ci		if (status) {
9398c2ecf20Sopenharmony_ci			test->flags |= ETH_TEST_FL_FAILED;
9408c2ecf20Sopenharmony_ci			data[4] = -1;
9418c2ecf20Sopenharmony_ci			break;
9428c2ecf20Sopenharmony_ci		}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		if (link_status)
9458c2ecf20Sopenharmony_ci			break;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		msleep_interruptible(500);
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic int be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return be_load_fw(adapter, efl->data);
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic int
9598c2ecf20Sopenharmony_cibe_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	if (!check_privilege(adapter, MAX_PRIVILEGES))
9648c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	dump->len = be_get_dump_len(adapter);
9678c2ecf20Sopenharmony_ci	dump->version = 1;
9688c2ecf20Sopenharmony_ci	dump->flag = 0x1;	/* FW dump is enabled */
9698c2ecf20Sopenharmony_ci	return 0;
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_cistatic int
9738c2ecf20Sopenharmony_cibe_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
9748c2ecf20Sopenharmony_ci		 void *buf)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
9778c2ecf20Sopenharmony_ci	int status;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (!check_privilege(adapter, MAX_PRIVILEGES))
9808c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	status = be_read_dump_data(adapter, dump->len, buf);
9838c2ecf20Sopenharmony_ci	return be_cmd_status(status);
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic int be_get_eeprom_len(struct net_device *netdev)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	if (!check_privilege(adapter, MAX_PRIVILEGES))
9918c2ecf20Sopenharmony_ci		return 0;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (lancer_chip(adapter)) {
9948c2ecf20Sopenharmony_ci		if (be_physfn(adapter))
9958c2ecf20Sopenharmony_ci			return lancer_cmd_get_file_len(adapter,
9968c2ecf20Sopenharmony_ci						       LANCER_VPD_PF_FILE);
9978c2ecf20Sopenharmony_ci		else
9988c2ecf20Sopenharmony_ci			return lancer_cmd_get_file_len(adapter,
9998c2ecf20Sopenharmony_ci						       LANCER_VPD_VF_FILE);
10008c2ecf20Sopenharmony_ci	} else {
10018c2ecf20Sopenharmony_ci		return BE_READ_SEEPROM_LEN;
10028c2ecf20Sopenharmony_ci	}
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic int be_read_eeprom(struct net_device *netdev,
10068c2ecf20Sopenharmony_ci			  struct ethtool_eeprom *eeprom, uint8_t *data)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
10098c2ecf20Sopenharmony_ci	struct be_dma_mem eeprom_cmd;
10108c2ecf20Sopenharmony_ci	struct be_cmd_resp_seeprom_read *resp;
10118c2ecf20Sopenharmony_ci	int status;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (!eeprom->len)
10148c2ecf20Sopenharmony_ci		return -EINVAL;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (lancer_chip(adapter)) {
10178c2ecf20Sopenharmony_ci		if (be_physfn(adapter))
10188c2ecf20Sopenharmony_ci			return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE,
10198c2ecf20Sopenharmony_ci						    eeprom->len, data);
10208c2ecf20Sopenharmony_ci		else
10218c2ecf20Sopenharmony_ci			return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE,
10228c2ecf20Sopenharmony_ci						    eeprom->len, data);
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
10288c2ecf20Sopenharmony_ci	eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
10298c2ecf20Sopenharmony_ci	eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev,
10308c2ecf20Sopenharmony_ci					   eeprom_cmd.size, &eeprom_cmd.dma,
10318c2ecf20Sopenharmony_ci					   GFP_KERNEL);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	if (!eeprom_cmd.va)
10348c2ecf20Sopenharmony_ci		return -ENOMEM;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	if (!status) {
10398c2ecf20Sopenharmony_ci		resp = eeprom_cmd.va;
10408c2ecf20Sopenharmony_ci		memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len);
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci	dma_free_coherent(&adapter->pdev->dev, eeprom_cmd.size, eeprom_cmd.va,
10438c2ecf20Sopenharmony_ci			  eeprom_cmd.dma);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	return be_cmd_status(status);
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_cistatic u32 be_get_msg_level(struct net_device *netdev)
10498c2ecf20Sopenharmony_ci{
10508c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	return adapter->msg_enable;
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic void be_set_msg_level(struct net_device *netdev, u32 level)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	if (adapter->msg_enable == level)
10608c2ecf20Sopenharmony_ci		return;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW))
10638c2ecf20Sopenharmony_ci		if (BEx_chip(adapter))
10648c2ecf20Sopenharmony_ci			be_cmd_set_fw_log_level(adapter, level & NETIF_MSG_HW ?
10658c2ecf20Sopenharmony_ci						FW_LOG_LEVEL_DEFAULT :
10668c2ecf20Sopenharmony_ci						FW_LOG_LEVEL_FATAL);
10678c2ecf20Sopenharmony_ci	adapter->msg_enable = level;
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	u64 data = 0;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	switch (flow_type) {
10758c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
10768c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4)
10778c2ecf20Sopenharmony_ci			data |= RXH_IP_DST | RXH_IP_SRC;
10788c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV4)
10798c2ecf20Sopenharmony_ci			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10808c2ecf20Sopenharmony_ci		break;
10818c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
10828c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV4)
10838c2ecf20Sopenharmony_ci			data |= RXH_IP_DST | RXH_IP_SRC;
10848c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV4)
10858c2ecf20Sopenharmony_ci			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10868c2ecf20Sopenharmony_ci		break;
10878c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
10888c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6)
10898c2ecf20Sopenharmony_ci			data |= RXH_IP_DST | RXH_IP_SRC;
10908c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_TCP_IPV6)
10918c2ecf20Sopenharmony_ci			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10928c2ecf20Sopenharmony_ci		break;
10938c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
10948c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_IPV6)
10958c2ecf20Sopenharmony_ci			data |= RXH_IP_DST | RXH_IP_SRC;
10968c2ecf20Sopenharmony_ci		if (adapter->rss_info.rss_flags & RSS_ENABLE_UDP_IPV6)
10978c2ecf20Sopenharmony_ci			data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
10988c2ecf20Sopenharmony_ci		break;
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	return data;
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_cistatic int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
11058c2ecf20Sopenharmony_ci			u32 *rule_locs)
11068c2ecf20Sopenharmony_ci{
11078c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	if (!be_multi_rxq(adapter)) {
11108c2ecf20Sopenharmony_ci		dev_info(&adapter->pdev->dev,
11118c2ecf20Sopenharmony_ci			 "ethtool::get_rxnfc: RX flow hashing is disabled\n");
11128c2ecf20Sopenharmony_ci		return -EINVAL;
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
11168c2ecf20Sopenharmony_ci	case ETHTOOL_GRXFH:
11178c2ecf20Sopenharmony_ci		cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type);
11188c2ecf20Sopenharmony_ci		break;
11198c2ecf20Sopenharmony_ci	case ETHTOOL_GRXRINGS:
11208c2ecf20Sopenharmony_ci		cmd->data = adapter->num_rx_qs;
11218c2ecf20Sopenharmony_ci		break;
11228c2ecf20Sopenharmony_ci	default:
11238c2ecf20Sopenharmony_ci		return -EINVAL;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	return 0;
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic int be_set_rss_hash_opts(struct be_adapter *adapter,
11308c2ecf20Sopenharmony_ci				struct ethtool_rxnfc *cmd)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	int status;
11338c2ecf20Sopenharmony_ci	u32 rss_flags = adapter->rss_info.rss_flags;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (cmd->data != L3_RSS_FLAGS &&
11368c2ecf20Sopenharmony_ci	    cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS))
11378c2ecf20Sopenharmony_ci		return -EINVAL;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	switch (cmd->flow_type) {
11408c2ecf20Sopenharmony_ci	case TCP_V4_FLOW:
11418c2ecf20Sopenharmony_ci		if (cmd->data == L3_RSS_FLAGS)
11428c2ecf20Sopenharmony_ci			rss_flags &= ~RSS_ENABLE_TCP_IPV4;
11438c2ecf20Sopenharmony_ci		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
11448c2ecf20Sopenharmony_ci			rss_flags |= RSS_ENABLE_IPV4 |
11458c2ecf20Sopenharmony_ci					RSS_ENABLE_TCP_IPV4;
11468c2ecf20Sopenharmony_ci		break;
11478c2ecf20Sopenharmony_ci	case TCP_V6_FLOW:
11488c2ecf20Sopenharmony_ci		if (cmd->data == L3_RSS_FLAGS)
11498c2ecf20Sopenharmony_ci			rss_flags &= ~RSS_ENABLE_TCP_IPV6;
11508c2ecf20Sopenharmony_ci		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
11518c2ecf20Sopenharmony_ci			rss_flags |= RSS_ENABLE_IPV6 |
11528c2ecf20Sopenharmony_ci					RSS_ENABLE_TCP_IPV6;
11538c2ecf20Sopenharmony_ci		break;
11548c2ecf20Sopenharmony_ci	case UDP_V4_FLOW:
11558c2ecf20Sopenharmony_ci		if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) &&
11568c2ecf20Sopenharmony_ci		    BEx_chip(adapter))
11578c2ecf20Sopenharmony_ci			return -EINVAL;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci		if (cmd->data == L3_RSS_FLAGS)
11608c2ecf20Sopenharmony_ci			rss_flags &= ~RSS_ENABLE_UDP_IPV4;
11618c2ecf20Sopenharmony_ci		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
11628c2ecf20Sopenharmony_ci			rss_flags |= RSS_ENABLE_IPV4 |
11638c2ecf20Sopenharmony_ci					RSS_ENABLE_UDP_IPV4;
11648c2ecf20Sopenharmony_ci		break;
11658c2ecf20Sopenharmony_ci	case UDP_V6_FLOW:
11668c2ecf20Sopenharmony_ci		if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) &&
11678c2ecf20Sopenharmony_ci		    BEx_chip(adapter))
11688c2ecf20Sopenharmony_ci			return -EINVAL;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci		if (cmd->data == L3_RSS_FLAGS)
11718c2ecf20Sopenharmony_ci			rss_flags &= ~RSS_ENABLE_UDP_IPV6;
11728c2ecf20Sopenharmony_ci		else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
11738c2ecf20Sopenharmony_ci			rss_flags |= RSS_ENABLE_IPV6 |
11748c2ecf20Sopenharmony_ci					RSS_ENABLE_UDP_IPV6;
11758c2ecf20Sopenharmony_ci		break;
11768c2ecf20Sopenharmony_ci	default:
11778c2ecf20Sopenharmony_ci		return -EINVAL;
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (rss_flags == adapter->rss_info.rss_flags)
11818c2ecf20Sopenharmony_ci		return 0;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable,
11848c2ecf20Sopenharmony_ci				   rss_flags, RSS_INDIR_TABLE_LEN,
11858c2ecf20Sopenharmony_ci				   adapter->rss_info.rss_hkey);
11868c2ecf20Sopenharmony_ci	if (!status)
11878c2ecf20Sopenharmony_ci		adapter->rss_info.rss_flags = rss_flags;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	return be_cmd_status(status);
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_cistatic int be_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
11958c2ecf20Sopenharmony_ci	int status = 0;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	if (!be_multi_rxq(adapter)) {
11988c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev,
11998c2ecf20Sopenharmony_ci			"ethtool::set_rxnfc: RX flow hashing is disabled\n");
12008c2ecf20Sopenharmony_ci		return -EINVAL;
12018c2ecf20Sopenharmony_ci	}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	switch (cmd->cmd) {
12048c2ecf20Sopenharmony_ci	case ETHTOOL_SRXFH:
12058c2ecf20Sopenharmony_ci		status = be_set_rss_hash_opts(adapter, cmd);
12068c2ecf20Sopenharmony_ci		break;
12078c2ecf20Sopenharmony_ci	default:
12088c2ecf20Sopenharmony_ci		return -EINVAL;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	return status;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic void be_get_channels(struct net_device *netdev,
12158c2ecf20Sopenharmony_ci			    struct ethtool_channels *ch)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
12188c2ecf20Sopenharmony_ci	u16 num_rx_irqs = max_t(u16, adapter->num_rss_qs, 1);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	/* num_tx_qs is always same as the number of irqs used for TX */
12218c2ecf20Sopenharmony_ci	ch->combined_count = min(adapter->num_tx_qs, num_rx_irqs);
12228c2ecf20Sopenharmony_ci	ch->rx_count = num_rx_irqs - ch->combined_count;
12238c2ecf20Sopenharmony_ci	ch->tx_count = adapter->num_tx_qs - ch->combined_count;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	ch->max_combined = be_max_qp_irqs(adapter);
12268c2ecf20Sopenharmony_ci	/* The user must create atleast one combined channel */
12278c2ecf20Sopenharmony_ci	ch->max_rx = be_max_rx_irqs(adapter) - 1;
12288c2ecf20Sopenharmony_ci	ch->max_tx = be_max_tx_irqs(adapter) - 1;
12298c2ecf20Sopenharmony_ci}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_cistatic int be_set_channels(struct net_device  *netdev,
12328c2ecf20Sopenharmony_ci			   struct ethtool_channels *ch)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
12358c2ecf20Sopenharmony_ci	int status;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	/* we support either only combined channels or a combination of
12388c2ecf20Sopenharmony_ci	 * combined and either RX-only or TX-only channels.
12398c2ecf20Sopenharmony_ci	 */
12408c2ecf20Sopenharmony_ci	if (ch->other_count || !ch->combined_count ||
12418c2ecf20Sopenharmony_ci	    (ch->rx_count && ch->tx_count))
12428c2ecf20Sopenharmony_ci		return -EINVAL;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	if (ch->combined_count > be_max_qp_irqs(adapter) ||
12458c2ecf20Sopenharmony_ci	    (ch->rx_count &&
12468c2ecf20Sopenharmony_ci	     (ch->rx_count + ch->combined_count) > be_max_rx_irqs(adapter)) ||
12478c2ecf20Sopenharmony_ci	    (ch->tx_count &&
12488c2ecf20Sopenharmony_ci	     (ch->tx_count + ch->combined_count) > be_max_tx_irqs(adapter)))
12498c2ecf20Sopenharmony_ci		return -EINVAL;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	adapter->cfg_num_rx_irqs = ch->combined_count + ch->rx_count;
12528c2ecf20Sopenharmony_ci	adapter->cfg_num_tx_irqs = ch->combined_count + ch->tx_count;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	status = be_update_queues(adapter);
12558c2ecf20Sopenharmony_ci	return be_cmd_status(status);
12568c2ecf20Sopenharmony_ci}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_cistatic u32 be_get_rxfh_indir_size(struct net_device *netdev)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	return RSS_INDIR_TABLE_LEN;
12618c2ecf20Sopenharmony_ci}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic u32 be_get_rxfh_key_size(struct net_device *netdev)
12648c2ecf20Sopenharmony_ci{
12658c2ecf20Sopenharmony_ci	return RSS_HASH_KEY_LEN;
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey,
12698c2ecf20Sopenharmony_ci		       u8 *hfunc)
12708c2ecf20Sopenharmony_ci{
12718c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
12728c2ecf20Sopenharmony_ci	int i;
12738c2ecf20Sopenharmony_ci	struct rss_info *rss = &adapter->rss_info;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	if (indir) {
12768c2ecf20Sopenharmony_ci		for (i = 0; i < RSS_INDIR_TABLE_LEN; i++)
12778c2ecf20Sopenharmony_ci			indir[i] = rss->rss_queue[i];
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	if (hkey)
12818c2ecf20Sopenharmony_ci		memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	if (hfunc)
12848c2ecf20Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	return 0;
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_cistatic int be_set_rxfh(struct net_device *netdev, const u32 *indir,
12908c2ecf20Sopenharmony_ci		       const u8 *hkey, const u8 hfunc)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	int rc = 0, i, j;
12938c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
12948c2ecf20Sopenharmony_ci	u8 rsstable[RSS_INDIR_TABLE_LEN];
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	/* We do not allow change in unsupported parameters */
12978c2ecf20Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
12988c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (indir) {
13018c2ecf20Sopenharmony_ci		struct be_rx_obj *rxo;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) {
13048c2ecf20Sopenharmony_ci			j = indir[i];
13058c2ecf20Sopenharmony_ci			rxo = &adapter->rx_obj[j];
13068c2ecf20Sopenharmony_ci			rsstable[i] = rxo->rss_id;
13078c2ecf20Sopenharmony_ci			adapter->rss_info.rss_queue[i] = j;
13088c2ecf20Sopenharmony_ci		}
13098c2ecf20Sopenharmony_ci	} else {
13108c2ecf20Sopenharmony_ci		memcpy(rsstable, adapter->rss_info.rsstable,
13118c2ecf20Sopenharmony_ci		       RSS_INDIR_TABLE_LEN);
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if (!hkey)
13158c2ecf20Sopenharmony_ci		hkey =  adapter->rss_info.rss_hkey;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	rc = be_cmd_rss_config(adapter, rsstable,
13188c2ecf20Sopenharmony_ci			       adapter->rss_info.rss_flags,
13198c2ecf20Sopenharmony_ci			       RSS_INDIR_TABLE_LEN, hkey);
13208c2ecf20Sopenharmony_ci	if (rc) {
13218c2ecf20Sopenharmony_ci		adapter->rss_info.rss_flags = RSS_ENABLE_NONE;
13228c2ecf20Sopenharmony_ci		return -EIO;
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci	memcpy(adapter->rss_info.rss_hkey, hkey, RSS_HASH_KEY_LEN);
13258c2ecf20Sopenharmony_ci	memcpy(adapter->rss_info.rsstable, rsstable,
13268c2ecf20Sopenharmony_ci	       RSS_INDIR_TABLE_LEN);
13278c2ecf20Sopenharmony_ci	return 0;
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_cistatic int be_get_module_info(struct net_device *netdev,
13318c2ecf20Sopenharmony_ci			      struct ethtool_modinfo *modinfo)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
13348c2ecf20Sopenharmony_ci	u8 page_data[PAGE_DATA_LEN];
13358c2ecf20Sopenharmony_ci	int status;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	if (!check_privilege(adapter, MAX_PRIVILEGES))
13388c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
13418c2ecf20Sopenharmony_ci						   0, PAGE_DATA_LEN, page_data);
13428c2ecf20Sopenharmony_ci	if (!status) {
13438c2ecf20Sopenharmony_ci		if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
13448c2ecf20Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8079;
13458c2ecf20Sopenharmony_ci			modinfo->eeprom_len = PAGE_DATA_LEN;
13468c2ecf20Sopenharmony_ci		} else {
13478c2ecf20Sopenharmony_ci			modinfo->type = ETH_MODULE_SFF_8472;
13488c2ecf20Sopenharmony_ci			modinfo->eeprom_len = 2 * PAGE_DATA_LEN;
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci	return be_cmd_status(status);
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_cistatic int be_get_module_eeprom(struct net_device *netdev,
13558c2ecf20Sopenharmony_ci				struct ethtool_eeprom *eeprom, u8 *data)
13568c2ecf20Sopenharmony_ci{
13578c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
13588c2ecf20Sopenharmony_ci	int status;
13598c2ecf20Sopenharmony_ci	u32 begin, end;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (!check_privilege(adapter, MAX_PRIVILEGES))
13628c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	begin = eeprom->offset;
13658c2ecf20Sopenharmony_ci	end = eeprom->offset + eeprom->len;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	if (begin < PAGE_DATA_LEN) {
13688c2ecf20Sopenharmony_ci		status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, begin,
13698c2ecf20Sopenharmony_ci							   min_t(u32, end, PAGE_DATA_LEN) - begin,
13708c2ecf20Sopenharmony_ci							   data);
13718c2ecf20Sopenharmony_ci		if (status)
13728c2ecf20Sopenharmony_ci			goto err;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci		data += PAGE_DATA_LEN - begin;
13758c2ecf20Sopenharmony_ci		begin = PAGE_DATA_LEN;
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (end > PAGE_DATA_LEN) {
13798c2ecf20Sopenharmony_ci		status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2,
13808c2ecf20Sopenharmony_ci							   begin - PAGE_DATA_LEN,
13818c2ecf20Sopenharmony_ci							   end - begin, data);
13828c2ecf20Sopenharmony_ci		if (status)
13838c2ecf20Sopenharmony_ci			goto err;
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_cierr:
13868c2ecf20Sopenharmony_ci	return be_cmd_status(status);
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistatic u32 be_get_priv_flags(struct net_device *netdev)
13908c2ecf20Sopenharmony_ci{
13918c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	return adapter->priv_flags;
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_cistatic int be_set_priv_flags(struct net_device *netdev, u32 flags)
13978c2ecf20Sopenharmony_ci{
13988c2ecf20Sopenharmony_ci	struct be_adapter *adapter = netdev_priv(netdev);
13998c2ecf20Sopenharmony_ci	bool tpe_old = !!(adapter->priv_flags & BE_DISABLE_TPE_RECOVERY);
14008c2ecf20Sopenharmony_ci	bool tpe_new = !!(flags & BE_DISABLE_TPE_RECOVERY);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (tpe_old != tpe_new) {
14038c2ecf20Sopenharmony_ci		if (tpe_new) {
14048c2ecf20Sopenharmony_ci			adapter->priv_flags |= BE_DISABLE_TPE_RECOVERY;
14058c2ecf20Sopenharmony_ci			dev_info(&adapter->pdev->dev,
14068c2ecf20Sopenharmony_ci				 "HW error recovery is disabled\n");
14078c2ecf20Sopenharmony_ci		} else {
14088c2ecf20Sopenharmony_ci			adapter->priv_flags &= ~BE_DISABLE_TPE_RECOVERY;
14098c2ecf20Sopenharmony_ci			dev_info(&adapter->pdev->dev,
14108c2ecf20Sopenharmony_ci				 "HW error recovery is enabled\n");
14118c2ecf20Sopenharmony_ci		}
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	return 0;
14158c2ecf20Sopenharmony_ci}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ciconst struct ethtool_ops be_ethtool_ops = {
14188c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
14198c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE |
14208c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_USECS_LOW_HIGH,
14218c2ecf20Sopenharmony_ci	.get_drvinfo = be_get_drvinfo,
14228c2ecf20Sopenharmony_ci	.get_wol = be_get_wol,
14238c2ecf20Sopenharmony_ci	.set_wol = be_set_wol,
14248c2ecf20Sopenharmony_ci	.get_link = ethtool_op_get_link,
14258c2ecf20Sopenharmony_ci	.get_eeprom_len = be_get_eeprom_len,
14268c2ecf20Sopenharmony_ci	.get_eeprom = be_read_eeprom,
14278c2ecf20Sopenharmony_ci	.get_coalesce = be_get_coalesce,
14288c2ecf20Sopenharmony_ci	.set_coalesce = be_set_coalesce,
14298c2ecf20Sopenharmony_ci	.get_ringparam = be_get_ringparam,
14308c2ecf20Sopenharmony_ci	.get_pauseparam = be_get_pauseparam,
14318c2ecf20Sopenharmony_ci	.set_pauseparam = be_set_pauseparam,
14328c2ecf20Sopenharmony_ci	.set_priv_flags = be_set_priv_flags,
14338c2ecf20Sopenharmony_ci	.get_priv_flags = be_get_priv_flags,
14348c2ecf20Sopenharmony_ci	.get_strings = be_get_stat_strings,
14358c2ecf20Sopenharmony_ci	.set_phys_id = be_set_phys_id,
14368c2ecf20Sopenharmony_ci	.set_dump = be_set_dump,
14378c2ecf20Sopenharmony_ci	.get_msglevel = be_get_msg_level,
14388c2ecf20Sopenharmony_ci	.set_msglevel = be_set_msg_level,
14398c2ecf20Sopenharmony_ci	.get_sset_count = be_get_sset_count,
14408c2ecf20Sopenharmony_ci	.get_ethtool_stats = be_get_ethtool_stats,
14418c2ecf20Sopenharmony_ci	.flash_device = be_do_flash,
14428c2ecf20Sopenharmony_ci	.self_test = be_self_test,
14438c2ecf20Sopenharmony_ci	.get_rxnfc = be_get_rxnfc,
14448c2ecf20Sopenharmony_ci	.set_rxnfc = be_set_rxnfc,
14458c2ecf20Sopenharmony_ci	.get_rxfh_indir_size = be_get_rxfh_indir_size,
14468c2ecf20Sopenharmony_ci	.get_rxfh_key_size = be_get_rxfh_key_size,
14478c2ecf20Sopenharmony_ci	.get_rxfh = be_get_rxfh,
14488c2ecf20Sopenharmony_ci	.set_rxfh = be_set_rxfh,
14498c2ecf20Sopenharmony_ci	.get_dump_flag = be_get_dump_flag,
14508c2ecf20Sopenharmony_ci	.get_dump_data = be_get_dump_data,
14518c2ecf20Sopenharmony_ci	.get_channels = be_get_channels,
14528c2ecf20Sopenharmony_ci	.set_channels = be_set_channels,
14538c2ecf20Sopenharmony_ci	.get_module_info = be_get_module_info,
14548c2ecf20Sopenharmony_ci	.get_module_eeprom = be_get_module_eeprom,
14558c2ecf20Sopenharmony_ci	.get_link_ksettings = be_get_link_ksettings,
14568c2ecf20Sopenharmony_ci};
1457