xref: /linux/drivers/net/ethernet/brocade/bna/bnad_ethtool.c (revision b3cc6e88d5346b89275b150ecd1281628f058498)
18b230ed8SRasesh Mody /*
28b230ed8SRasesh Mody  * Linux network driver for Brocade Converged Network Adapter.
38b230ed8SRasesh Mody  *
48b230ed8SRasesh Mody  * This program is free software; you can redistribute it and/or modify it
58b230ed8SRasesh Mody  * under the terms of the GNU General Public License (GPL) Version 2 as
68b230ed8SRasesh Mody  * published by the Free Software Foundation
78b230ed8SRasesh Mody  *
88b230ed8SRasesh Mody  * This program is distributed in the hope that it will be useful, but
98b230ed8SRasesh Mody  * WITHOUT ANY WARRANTY; without even the implied warranty of
108b230ed8SRasesh Mody  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
118b230ed8SRasesh Mody  * General Public License for more details.
128b230ed8SRasesh Mody  */
138b230ed8SRasesh Mody /*
148b230ed8SRasesh Mody  * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
158b230ed8SRasesh Mody  * All rights reserved
168b230ed8SRasesh Mody  * www.brocade.com
178b230ed8SRasesh Mody  */
188b230ed8SRasesh Mody 
198b230ed8SRasesh Mody #include "cna.h"
208b230ed8SRasesh Mody 
218b230ed8SRasesh Mody #include <linux/netdevice.h>
228b230ed8SRasesh Mody #include <linux/skbuff.h>
238b230ed8SRasesh Mody #include <linux/ethtool.h>
248b230ed8SRasesh Mody #include <linux/rtnetlink.h>
258b230ed8SRasesh Mody 
268b230ed8SRasesh Mody #include "bna.h"
278b230ed8SRasesh Mody 
288b230ed8SRasesh Mody #include "bnad.h"
298b230ed8SRasesh Mody 
308b230ed8SRasesh Mody #define BNAD_NUM_TXF_COUNTERS 12
318b230ed8SRasesh Mody #define BNAD_NUM_RXF_COUNTERS 10
32078086f3SRasesh Mody #define BNAD_NUM_CQ_COUNTERS (3 + 5)
338b230ed8SRasesh Mody #define BNAD_NUM_RXQ_COUNTERS 6
348b230ed8SRasesh Mody #define BNAD_NUM_TXQ_COUNTERS 5
358b230ed8SRasesh Mody 
368b230ed8SRasesh Mody #define BNAD_ETHTOOL_STATS_NUM						\
37250e061eSEric Dumazet 	(sizeof(struct rtnl_link_stats64) / sizeof(u64) +	\
388b230ed8SRasesh Mody 	sizeof(struct bnad_drv_stats) / sizeof(u64) +		\
39078086f3SRasesh Mody 	offsetof(struct bfi_enet_stats, rxf_stats[0]) / sizeof(u64))
408b230ed8SRasesh Mody 
41975419cfSstephen hemminger static const char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
428b230ed8SRasesh Mody 	"rx_packets",
438b230ed8SRasesh Mody 	"tx_packets",
448b230ed8SRasesh Mody 	"rx_bytes",
458b230ed8SRasesh Mody 	"tx_bytes",
468b230ed8SRasesh Mody 	"rx_errors",
478b230ed8SRasesh Mody 	"tx_errors",
488b230ed8SRasesh Mody 	"rx_dropped",
498b230ed8SRasesh Mody 	"tx_dropped",
508b230ed8SRasesh Mody 	"multicast",
518b230ed8SRasesh Mody 	"collisions",
528b230ed8SRasesh Mody 
538b230ed8SRasesh Mody 	"rx_length_errors",
548b230ed8SRasesh Mody 	"rx_over_errors",
558b230ed8SRasesh Mody 	"rx_crc_errors",
568b230ed8SRasesh Mody 	"rx_frame_errors",
578b230ed8SRasesh Mody 	"rx_fifo_errors",
588b230ed8SRasesh Mody 	"rx_missed_errors",
598b230ed8SRasesh Mody 
608b230ed8SRasesh Mody 	"tx_aborted_errors",
618b230ed8SRasesh Mody 	"tx_carrier_errors",
628b230ed8SRasesh Mody 	"tx_fifo_errors",
638b230ed8SRasesh Mody 	"tx_heartbeat_errors",
648b230ed8SRasesh Mody 	"tx_window_errors",
658b230ed8SRasesh Mody 
668b230ed8SRasesh Mody 	"rx_compressed",
678b230ed8SRasesh Mody 	"tx_compressed",
688b230ed8SRasesh Mody 
698b230ed8SRasesh Mody 	"netif_queue_stop",
708b230ed8SRasesh Mody 	"netif_queue_wakeup",
71f7c0fa4cSRasesh Mody 	"netif_queue_stopped",
728b230ed8SRasesh Mody 	"tso4",
738b230ed8SRasesh Mody 	"tso6",
748b230ed8SRasesh Mody 	"tso_err",
758b230ed8SRasesh Mody 	"tcpcsum_offload",
768b230ed8SRasesh Mody 	"udpcsum_offload",
778b230ed8SRasesh Mody 	"csum_help",
78a2122d95SRasesh Mody 	"tx_skb_too_short",
79a2122d95SRasesh Mody 	"tx_skb_stopping",
80a2122d95SRasesh Mody 	"tx_skb_max_vectors",
81a2122d95SRasesh Mody 	"tx_skb_mss_too_long",
82a2122d95SRasesh Mody 	"tx_skb_tso_too_short",
83a2122d95SRasesh Mody 	"tx_skb_tso_prepare",
84a2122d95SRasesh Mody 	"tx_skb_non_tso_too_long",
85a2122d95SRasesh Mody 	"tx_skb_tcp_hdr",
86a2122d95SRasesh Mody 	"tx_skb_udp_hdr",
87a2122d95SRasesh Mody 	"tx_skb_csum_err",
88a2122d95SRasesh Mody 	"tx_skb_headlen_too_long",
89a2122d95SRasesh Mody 	"tx_skb_headlen_zero",
90a2122d95SRasesh Mody 	"tx_skb_frag_zero",
91a2122d95SRasesh Mody 	"tx_skb_len_mismatch",
928b230ed8SRasesh Mody 	"hw_stats_updates",
938b230ed8SRasesh Mody 	"netif_rx_dropped",
948b230ed8SRasesh Mody 
958b230ed8SRasesh Mody 	"link_toggle",
96a2122d95SRasesh Mody 	"cee_toggle",
978b230ed8SRasesh Mody 
988b230ed8SRasesh Mody 	"rxp_info_alloc_failed",
998b230ed8SRasesh Mody 	"mbox_intr_disabled",
1008b230ed8SRasesh Mody 	"mbox_intr_enabled",
1018b230ed8SRasesh Mody 	"tx_unmap_q_alloc_failed",
1028b230ed8SRasesh Mody 	"rx_unmap_q_alloc_failed",
1038b230ed8SRasesh Mody 	"rxbuf_alloc_failed",
1048b230ed8SRasesh Mody 
1058b230ed8SRasesh Mody 	"mac_frame_64",
1068b230ed8SRasesh Mody 	"mac_frame_65_127",
1078b230ed8SRasesh Mody 	"mac_frame_128_255",
1088b230ed8SRasesh Mody 	"mac_frame_256_511",
1098b230ed8SRasesh Mody 	"mac_frame_512_1023",
1108b230ed8SRasesh Mody 	"mac_frame_1024_1518",
1118b230ed8SRasesh Mody 	"mac_frame_1518_1522",
1128b230ed8SRasesh Mody 	"mac_rx_bytes",
1138b230ed8SRasesh Mody 	"mac_rx_packets",
1148b230ed8SRasesh Mody 	"mac_rx_fcs_error",
1158b230ed8SRasesh Mody 	"mac_rx_multicast",
1168b230ed8SRasesh Mody 	"mac_rx_broadcast",
1178b230ed8SRasesh Mody 	"mac_rx_control_frames",
1188b230ed8SRasesh Mody 	"mac_rx_pause",
1198b230ed8SRasesh Mody 	"mac_rx_unknown_opcode",
1208b230ed8SRasesh Mody 	"mac_rx_alignment_error",
1218b230ed8SRasesh Mody 	"mac_rx_frame_length_error",
1228b230ed8SRasesh Mody 	"mac_rx_code_error",
1238b230ed8SRasesh Mody 	"mac_rx_carrier_sense_error",
1248b230ed8SRasesh Mody 	"mac_rx_undersize",
1258b230ed8SRasesh Mody 	"mac_rx_oversize",
1268b230ed8SRasesh Mody 	"mac_rx_fragments",
1278b230ed8SRasesh Mody 	"mac_rx_jabber",
1288b230ed8SRasesh Mody 	"mac_rx_drop",
1298b230ed8SRasesh Mody 
1308b230ed8SRasesh Mody 	"mac_tx_bytes",
1318b230ed8SRasesh Mody 	"mac_tx_packets",
1328b230ed8SRasesh Mody 	"mac_tx_multicast",
1338b230ed8SRasesh Mody 	"mac_tx_broadcast",
1348b230ed8SRasesh Mody 	"mac_tx_pause",
1358b230ed8SRasesh Mody 	"mac_tx_deferral",
1368b230ed8SRasesh Mody 	"mac_tx_excessive_deferral",
1378b230ed8SRasesh Mody 	"mac_tx_single_collision",
1388b230ed8SRasesh Mody 	"mac_tx_muliple_collision",
1398b230ed8SRasesh Mody 	"mac_tx_late_collision",
1408b230ed8SRasesh Mody 	"mac_tx_excessive_collision",
1418b230ed8SRasesh Mody 	"mac_tx_total_collision",
1428b230ed8SRasesh Mody 	"mac_tx_pause_honored",
1438b230ed8SRasesh Mody 	"mac_tx_drop",
1448b230ed8SRasesh Mody 	"mac_tx_jabber",
1458b230ed8SRasesh Mody 	"mac_tx_fcs_error",
1468b230ed8SRasesh Mody 	"mac_tx_control_frame",
1478b230ed8SRasesh Mody 	"mac_tx_oversize",
1488b230ed8SRasesh Mody 	"mac_tx_undersize",
1498b230ed8SRasesh Mody 	"mac_tx_fragments",
1508b230ed8SRasesh Mody 
1518b230ed8SRasesh Mody 	"bpc_tx_pause_0",
1528b230ed8SRasesh Mody 	"bpc_tx_pause_1",
1538b230ed8SRasesh Mody 	"bpc_tx_pause_2",
1548b230ed8SRasesh Mody 	"bpc_tx_pause_3",
1558b230ed8SRasesh Mody 	"bpc_tx_pause_4",
1568b230ed8SRasesh Mody 	"bpc_tx_pause_5",
1578b230ed8SRasesh Mody 	"bpc_tx_pause_6",
1588b230ed8SRasesh Mody 	"bpc_tx_pause_7",
1598b230ed8SRasesh Mody 	"bpc_tx_zero_pause_0",
1608b230ed8SRasesh Mody 	"bpc_tx_zero_pause_1",
1618b230ed8SRasesh Mody 	"bpc_tx_zero_pause_2",
1628b230ed8SRasesh Mody 	"bpc_tx_zero_pause_3",
1638b230ed8SRasesh Mody 	"bpc_tx_zero_pause_4",
1648b230ed8SRasesh Mody 	"bpc_tx_zero_pause_5",
1658b230ed8SRasesh Mody 	"bpc_tx_zero_pause_6",
1668b230ed8SRasesh Mody 	"bpc_tx_zero_pause_7",
1678b230ed8SRasesh Mody 	"bpc_tx_first_pause_0",
1688b230ed8SRasesh Mody 	"bpc_tx_first_pause_1",
1698b230ed8SRasesh Mody 	"bpc_tx_first_pause_2",
1708b230ed8SRasesh Mody 	"bpc_tx_first_pause_3",
1718b230ed8SRasesh Mody 	"bpc_tx_first_pause_4",
1728b230ed8SRasesh Mody 	"bpc_tx_first_pause_5",
1738b230ed8SRasesh Mody 	"bpc_tx_first_pause_6",
1748b230ed8SRasesh Mody 	"bpc_tx_first_pause_7",
1758b230ed8SRasesh Mody 
1768b230ed8SRasesh Mody 	"bpc_rx_pause_0",
1778b230ed8SRasesh Mody 	"bpc_rx_pause_1",
1788b230ed8SRasesh Mody 	"bpc_rx_pause_2",
1798b230ed8SRasesh Mody 	"bpc_rx_pause_3",
1808b230ed8SRasesh Mody 	"bpc_rx_pause_4",
1818b230ed8SRasesh Mody 	"bpc_rx_pause_5",
1828b230ed8SRasesh Mody 	"bpc_rx_pause_6",
1838b230ed8SRasesh Mody 	"bpc_rx_pause_7",
1848b230ed8SRasesh Mody 	"bpc_rx_zero_pause_0",
1858b230ed8SRasesh Mody 	"bpc_rx_zero_pause_1",
1868b230ed8SRasesh Mody 	"bpc_rx_zero_pause_2",
1878b230ed8SRasesh Mody 	"bpc_rx_zero_pause_3",
1888b230ed8SRasesh Mody 	"bpc_rx_zero_pause_4",
1898b230ed8SRasesh Mody 	"bpc_rx_zero_pause_5",
1908b230ed8SRasesh Mody 	"bpc_rx_zero_pause_6",
1918b230ed8SRasesh Mody 	"bpc_rx_zero_pause_7",
1928b230ed8SRasesh Mody 	"bpc_rx_first_pause_0",
1938b230ed8SRasesh Mody 	"bpc_rx_first_pause_1",
1948b230ed8SRasesh Mody 	"bpc_rx_first_pause_2",
1958b230ed8SRasesh Mody 	"bpc_rx_first_pause_3",
1968b230ed8SRasesh Mody 	"bpc_rx_first_pause_4",
1978b230ed8SRasesh Mody 	"bpc_rx_first_pause_5",
1988b230ed8SRasesh Mody 	"bpc_rx_first_pause_6",
1998b230ed8SRasesh Mody 	"bpc_rx_first_pause_7",
2008b230ed8SRasesh Mody 
2018b230ed8SRasesh Mody 	"rad_rx_frames",
2028b230ed8SRasesh Mody 	"rad_rx_octets",
2038b230ed8SRasesh Mody 	"rad_rx_vlan_frames",
2048b230ed8SRasesh Mody 	"rad_rx_ucast",
2058b230ed8SRasesh Mody 	"rad_rx_ucast_octets",
2068b230ed8SRasesh Mody 	"rad_rx_ucast_vlan",
2078b230ed8SRasesh Mody 	"rad_rx_mcast",
2088b230ed8SRasesh Mody 	"rad_rx_mcast_octets",
2098b230ed8SRasesh Mody 	"rad_rx_mcast_vlan",
2108b230ed8SRasesh Mody 	"rad_rx_bcast",
2118b230ed8SRasesh Mody 	"rad_rx_bcast_octets",
2128b230ed8SRasesh Mody 	"rad_rx_bcast_vlan",
2138b230ed8SRasesh Mody 	"rad_rx_drops",
2148b230ed8SRasesh Mody 
215a2122d95SRasesh Mody 	"rlb_rad_rx_frames",
216a2122d95SRasesh Mody 	"rlb_rad_rx_octets",
217a2122d95SRasesh Mody 	"rlb_rad_rx_vlan_frames",
218a2122d95SRasesh Mody 	"rlb_rad_rx_ucast",
219a2122d95SRasesh Mody 	"rlb_rad_rx_ucast_octets",
220a2122d95SRasesh Mody 	"rlb_rad_rx_ucast_vlan",
221a2122d95SRasesh Mody 	"rlb_rad_rx_mcast",
222a2122d95SRasesh Mody 	"rlb_rad_rx_mcast_octets",
223a2122d95SRasesh Mody 	"rlb_rad_rx_mcast_vlan",
224a2122d95SRasesh Mody 	"rlb_rad_rx_bcast",
225a2122d95SRasesh Mody 	"rlb_rad_rx_bcast_octets",
226a2122d95SRasesh Mody 	"rlb_rad_rx_bcast_vlan",
227a2122d95SRasesh Mody 	"rlb_rad_rx_drops",
228a2122d95SRasesh Mody 
2298b230ed8SRasesh Mody 	"fc_rx_ucast_octets",
2308b230ed8SRasesh Mody 	"fc_rx_ucast",
2318b230ed8SRasesh Mody 	"fc_rx_ucast_vlan",
2328b230ed8SRasesh Mody 	"fc_rx_mcast_octets",
2338b230ed8SRasesh Mody 	"fc_rx_mcast",
2348b230ed8SRasesh Mody 	"fc_rx_mcast_vlan",
2358b230ed8SRasesh Mody 	"fc_rx_bcast_octets",
2368b230ed8SRasesh Mody 	"fc_rx_bcast",
2378b230ed8SRasesh Mody 	"fc_rx_bcast_vlan",
2388b230ed8SRasesh Mody 
2398b230ed8SRasesh Mody 	"fc_tx_ucast_octets",
2408b230ed8SRasesh Mody 	"fc_tx_ucast",
2418b230ed8SRasesh Mody 	"fc_tx_ucast_vlan",
2428b230ed8SRasesh Mody 	"fc_tx_mcast_octets",
2438b230ed8SRasesh Mody 	"fc_tx_mcast",
2448b230ed8SRasesh Mody 	"fc_tx_mcast_vlan",
2458b230ed8SRasesh Mody 	"fc_tx_bcast_octets",
2468b230ed8SRasesh Mody 	"fc_tx_bcast",
2478b230ed8SRasesh Mody 	"fc_tx_bcast_vlan",
2488b230ed8SRasesh Mody 	"fc_tx_parity_errors",
2498b230ed8SRasesh Mody 	"fc_tx_timeout",
2508b230ed8SRasesh Mody 	"fc_tx_fid_parity_errors",
2518b230ed8SRasesh Mody };
2528b230ed8SRasesh Mody 
2538b230ed8SRasesh Mody static int
2548b230ed8SRasesh Mody bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
2558b230ed8SRasesh Mody {
2568b230ed8SRasesh Mody 	cmd->supported = SUPPORTED_10000baseT_Full;
2578b230ed8SRasesh Mody 	cmd->advertising = ADVERTISED_10000baseT_Full;
2588b230ed8SRasesh Mody 	cmd->autoneg = AUTONEG_DISABLE;
2598b230ed8SRasesh Mody 	cmd->supported |= SUPPORTED_FIBRE;
2608b230ed8SRasesh Mody 	cmd->advertising |= ADVERTISED_FIBRE;
2618b230ed8SRasesh Mody 	cmd->port = PORT_FIBRE;
2628b230ed8SRasesh Mody 	cmd->phy_address = 0;
2638b230ed8SRasesh Mody 
2648b230ed8SRasesh Mody 	if (netif_carrier_ok(netdev)) {
26570739497SDavid Decotigny 		ethtool_cmd_speed_set(cmd, SPEED_10000);
2668b230ed8SRasesh Mody 		cmd->duplex = DUPLEX_FULL;
2678b230ed8SRasesh Mody 	} else {
26870739497SDavid Decotigny 		ethtool_cmd_speed_set(cmd, -1);
2698b230ed8SRasesh Mody 		cmd->duplex = -1;
2708b230ed8SRasesh Mody 	}
2718b230ed8SRasesh Mody 	cmd->transceiver = XCVR_EXTERNAL;
2728b230ed8SRasesh Mody 	cmd->maxtxpkt = 0;
2738b230ed8SRasesh Mody 	cmd->maxrxpkt = 0;
2748b230ed8SRasesh Mody 
2758b230ed8SRasesh Mody 	return 0;
2768b230ed8SRasesh Mody }
2778b230ed8SRasesh Mody 
2788b230ed8SRasesh Mody static int
2798b230ed8SRasesh Mody bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
2808b230ed8SRasesh Mody {
2818b230ed8SRasesh Mody 	/* 10G full duplex setting supported only */
2828b230ed8SRasesh Mody 	if (cmd->autoneg == AUTONEG_ENABLE)
2838b230ed8SRasesh Mody 		return -EOPNOTSUPP; else {
28425db0338SDavid Decotigny 		if ((ethtool_cmd_speed(cmd) == SPEED_10000)
28525db0338SDavid Decotigny 		    && (cmd->duplex == DUPLEX_FULL))
2868b230ed8SRasesh Mody 			return 0;
2878b230ed8SRasesh Mody 	}
2888b230ed8SRasesh Mody 
2898b230ed8SRasesh Mody 	return -EOPNOTSUPP;
2908b230ed8SRasesh Mody }
2918b230ed8SRasesh Mody 
2928b230ed8SRasesh Mody static void
2938b230ed8SRasesh Mody bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
2948b230ed8SRasesh Mody {
2958b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
2968b230ed8SRasesh Mody 	struct bfa_ioc_attr *ioc_attr;
2978b230ed8SRasesh Mody 	unsigned long flags;
2988b230ed8SRasesh Mody 
29968aad78cSRick Jones 	strlcpy(drvinfo->driver, BNAD_NAME, sizeof(drvinfo->driver));
30068aad78cSRick Jones 	strlcpy(drvinfo->version, BNAD_VERSION, sizeof(drvinfo->version));
3018b230ed8SRasesh Mody 
3028b230ed8SRasesh Mody 	ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
3038b230ed8SRasesh Mody 	if (ioc_attr) {
3048b230ed8SRasesh Mody 		spin_lock_irqsave(&bnad->bna_lock, flags);
305078086f3SRasesh Mody 		bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr);
3068b230ed8SRasesh Mody 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
3078b230ed8SRasesh Mody 
30868aad78cSRick Jones 		strlcpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
30968aad78cSRick Jones 			sizeof(drvinfo->fw_version));
3108b230ed8SRasesh Mody 		kfree(ioc_attr);
3118b230ed8SRasesh Mody 	}
3128b230ed8SRasesh Mody 
31368aad78cSRick Jones 	strlcpy(drvinfo->bus_info, pci_name(bnad->pcidev),
31468aad78cSRick Jones 		sizeof(drvinfo->bus_info));
3158b230ed8SRasesh Mody }
3168b230ed8SRasesh Mody 
3178b230ed8SRasesh Mody static void
3188b230ed8SRasesh Mody bnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo)
3198b230ed8SRasesh Mody {
3208b230ed8SRasesh Mody 	wolinfo->supported = 0;
3218b230ed8SRasesh Mody 	wolinfo->wolopts = 0;
3228b230ed8SRasesh Mody }
3238b230ed8SRasesh Mody 
3248b230ed8SRasesh Mody static int
3258b230ed8SRasesh Mody bnad_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
3268b230ed8SRasesh Mody {
3278b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
3288b230ed8SRasesh Mody 	unsigned long flags;
3298b230ed8SRasesh Mody 
3308b230ed8SRasesh Mody 	/* Lock rqd. to access bnad->bna_lock */
3318b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
3328b230ed8SRasesh Mody 	coalesce->use_adaptive_rx_coalesce =
3338b230ed8SRasesh Mody 		(bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false;
3348b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
3358b230ed8SRasesh Mody 
3368b230ed8SRasesh Mody 	coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
3378b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT;
3388b230ed8SRasesh Mody 	coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
3398b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT;
3408b230ed8SRasesh Mody 	coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT;
3418b230ed8SRasesh Mody 
3428b230ed8SRasesh Mody 	return 0;
3438b230ed8SRasesh Mody }
3448b230ed8SRasesh Mody 
3458b230ed8SRasesh Mody static int
3468b230ed8SRasesh Mody bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
3478b230ed8SRasesh Mody {
3488b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
3498b230ed8SRasesh Mody 	unsigned long flags;
350a2122d95SRasesh Mody 	int to_del = 0;
3518b230ed8SRasesh Mody 
3528b230ed8SRasesh Mody 	if (coalesce->rx_coalesce_usecs == 0 ||
3538b230ed8SRasesh Mody 	    coalesce->rx_coalesce_usecs >
3548b230ed8SRasesh Mody 	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
3558b230ed8SRasesh Mody 		return -EINVAL;
3568b230ed8SRasesh Mody 
3578b230ed8SRasesh Mody 	if (coalesce->tx_coalesce_usecs == 0 ||
3588b230ed8SRasesh Mody 	    coalesce->tx_coalesce_usecs >
3598b230ed8SRasesh Mody 	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
3608b230ed8SRasesh Mody 		return -EINVAL;
3618b230ed8SRasesh Mody 
3628b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
3638b230ed8SRasesh Mody 	/*
3648b230ed8SRasesh Mody 	 * Do not need to store rx_coalesce_usecs here
3658b230ed8SRasesh Mody 	 * Every time DIM is disabled, we can get it from the
3668b230ed8SRasesh Mody 	 * stack.
3678b230ed8SRasesh Mody 	 */
3688b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
3698b230ed8SRasesh Mody 	if (coalesce->use_adaptive_rx_coalesce) {
3708b230ed8SRasesh Mody 		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) {
3718b230ed8SRasesh Mody 			bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
3728b230ed8SRasesh Mody 			bnad_dim_timer_start(bnad);
3738b230ed8SRasesh Mody 		}
3748b230ed8SRasesh Mody 	} else {
3758b230ed8SRasesh Mody 		if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) {
3768b230ed8SRasesh Mody 			bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED;
377a2122d95SRasesh Mody 			if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
378a2122d95SRasesh Mody 			    test_bit(BNAD_RF_DIM_TIMER_RUNNING,
379a2122d95SRasesh Mody 			    &bnad->run_flags)) {
3808b230ed8SRasesh Mody 				clear_bit(BNAD_RF_DIM_TIMER_RUNNING,
3818b230ed8SRasesh Mody 							&bnad->run_flags);
382a2122d95SRasesh Mody 				to_del = 1;
383a2122d95SRasesh Mody 			}
3848b230ed8SRasesh Mody 			spin_unlock_irqrestore(&bnad->bna_lock, flags);
385a2122d95SRasesh Mody 			if (to_del)
3868b230ed8SRasesh Mody 				del_timer_sync(&bnad->dim_timer);
3878b230ed8SRasesh Mody 			spin_lock_irqsave(&bnad->bna_lock, flags);
3888b230ed8SRasesh Mody 			bnad_rx_coalescing_timeo_set(bnad);
3898b230ed8SRasesh Mody 		}
3908b230ed8SRasesh Mody 	}
3918b230ed8SRasesh Mody 	if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs /
3928b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT) {
3938b230ed8SRasesh Mody 		bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
3948b230ed8SRasesh Mody 						BFI_COALESCING_TIMER_UNIT;
3958b230ed8SRasesh Mody 		bnad_tx_coalescing_timeo_set(bnad);
3968b230ed8SRasesh Mody 	}
3978b230ed8SRasesh Mody 
3988b230ed8SRasesh Mody 	if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs /
3998b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT) {
4008b230ed8SRasesh Mody 		bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
4018b230ed8SRasesh Mody 						BFI_COALESCING_TIMER_UNIT;
4028b230ed8SRasesh Mody 
4038b230ed8SRasesh Mody 		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED))
4048b230ed8SRasesh Mody 			bnad_rx_coalescing_timeo_set(bnad);
4058b230ed8SRasesh Mody 
4068b230ed8SRasesh Mody 	}
4078b230ed8SRasesh Mody 
4088b230ed8SRasesh Mody 	/* Add Tx Inter-pkt DMA count?  */
4098b230ed8SRasesh Mody 
4108b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
4118b230ed8SRasesh Mody 
4128b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
4138b230ed8SRasesh Mody 	return 0;
4148b230ed8SRasesh Mody }
4158b230ed8SRasesh Mody 
4168b230ed8SRasesh Mody static void
4178b230ed8SRasesh Mody bnad_get_ringparam(struct net_device *netdev,
4188b230ed8SRasesh Mody 		   struct ethtool_ringparam *ringparam)
4198b230ed8SRasesh Mody {
4208b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
4218b230ed8SRasesh Mody 
42241eb5ba4SRasesh Mody 	ringparam->rx_max_pending = BNAD_MAX_RXQ_DEPTH;
42341eb5ba4SRasesh Mody 	ringparam->tx_max_pending = BNAD_MAX_TXQ_DEPTH;
4248b230ed8SRasesh Mody 
4258b230ed8SRasesh Mody 	ringparam->rx_pending = bnad->rxq_depth;
4268b230ed8SRasesh Mody 	ringparam->tx_pending = bnad->txq_depth;
4278b230ed8SRasesh Mody }
4288b230ed8SRasesh Mody 
4298b230ed8SRasesh Mody static int
4308b230ed8SRasesh Mody bnad_set_ringparam(struct net_device *netdev,
4318b230ed8SRasesh Mody 		   struct ethtool_ringparam *ringparam)
4328b230ed8SRasesh Mody {
4338b230ed8SRasesh Mody 	int i, current_err, err = 0;
4348b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
435a2122d95SRasesh Mody 	unsigned long flags;
4368b230ed8SRasesh Mody 
4378b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
4388b230ed8SRasesh Mody 	if (ringparam->rx_pending == bnad->rxq_depth &&
4398b230ed8SRasesh Mody 	    ringparam->tx_pending == bnad->txq_depth) {
4408b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4418b230ed8SRasesh Mody 		return 0;
4428b230ed8SRasesh Mody 	}
4438b230ed8SRasesh Mody 
4448b230ed8SRasesh Mody 	if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
44541eb5ba4SRasesh Mody 	    ringparam->rx_pending > BNAD_MAX_RXQ_DEPTH ||
4468b230ed8SRasesh Mody 	    !BNA_POWER_OF_2(ringparam->rx_pending)) {
4478b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4488b230ed8SRasesh Mody 		return -EINVAL;
4498b230ed8SRasesh Mody 	}
4508b230ed8SRasesh Mody 	if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
45141eb5ba4SRasesh Mody 	    ringparam->tx_pending > BNAD_MAX_TXQ_DEPTH ||
4528b230ed8SRasesh Mody 	    !BNA_POWER_OF_2(ringparam->tx_pending)) {
4538b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4548b230ed8SRasesh Mody 		return -EINVAL;
4558b230ed8SRasesh Mody 	}
4568b230ed8SRasesh Mody 
4578b230ed8SRasesh Mody 	if (ringparam->rx_pending != bnad->rxq_depth) {
4588b230ed8SRasesh Mody 		bnad->rxq_depth = ringparam->rx_pending;
459a2122d95SRasesh Mody 		if (!netif_running(netdev)) {
460a2122d95SRasesh Mody 			mutex_unlock(&bnad->conf_mutex);
461a2122d95SRasesh Mody 			return 0;
462a2122d95SRasesh Mody 		}
463a2122d95SRasesh Mody 
4648b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
4658b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
4668b230ed8SRasesh Mody 				continue;
467*b3cc6e88SJing Huang 			bnad_destroy_rx(bnad, i);
4688b230ed8SRasesh Mody 			current_err = bnad_setup_rx(bnad, i);
4698b230ed8SRasesh Mody 			if (current_err && !err)
4708b230ed8SRasesh Mody 				err = current_err;
471a2122d95SRasesh Mody 		}
472a2122d95SRasesh Mody 
473a2122d95SRasesh Mody 		if (!err && bnad->rx_info[0].rx) {
474a2122d95SRasesh Mody 			/* restore rx configuration */
4753fb9852fSRasesh Mody 			bnad_restore_vlans(bnad, 0);
476a2122d95SRasesh Mody 			bnad_enable_default_bcast(bnad);
477a2122d95SRasesh Mody 			spin_lock_irqsave(&bnad->bna_lock, flags);
478a2122d95SRasesh Mody 			bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
479a2122d95SRasesh Mody 			spin_unlock_irqrestore(&bnad->bna_lock, flags);
4803fb9852fSRasesh Mody 			bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI |
4813fb9852fSRasesh Mody 					     BNAD_CF_PROMISC);
482a2122d95SRasesh Mody 			bnad_set_rx_mode(netdev);
4838b230ed8SRasesh Mody 		}
4848b230ed8SRasesh Mody 	}
4858b230ed8SRasesh Mody 	if (ringparam->tx_pending != bnad->txq_depth) {
4868b230ed8SRasesh Mody 		bnad->txq_depth = ringparam->tx_pending;
487a2122d95SRasesh Mody 		if (!netif_running(netdev)) {
488a2122d95SRasesh Mody 			mutex_unlock(&bnad->conf_mutex);
489a2122d95SRasesh Mody 			return 0;
490a2122d95SRasesh Mody 		}
491a2122d95SRasesh Mody 
4928b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_tx; i++) {
4938b230ed8SRasesh Mody 			if (!bnad->tx_info[i].tx)
4948b230ed8SRasesh Mody 				continue;
495*b3cc6e88SJing Huang 			bnad_destroy_tx(bnad, i);
4968b230ed8SRasesh Mody 			current_err = bnad_setup_tx(bnad, i);
4978b230ed8SRasesh Mody 			if (current_err && !err)
4988b230ed8SRasesh Mody 				err = current_err;
4998b230ed8SRasesh Mody 		}
5008b230ed8SRasesh Mody 	}
5018b230ed8SRasesh Mody 
5028b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
5038b230ed8SRasesh Mody 	return err;
5048b230ed8SRasesh Mody }
5058b230ed8SRasesh Mody 
5068b230ed8SRasesh Mody static void
5078b230ed8SRasesh Mody bnad_get_pauseparam(struct net_device *netdev,
5088b230ed8SRasesh Mody 		    struct ethtool_pauseparam *pauseparam)
5098b230ed8SRasesh Mody {
5108b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5118b230ed8SRasesh Mody 
5128b230ed8SRasesh Mody 	pauseparam->autoneg = 0;
513078086f3SRasesh Mody 	pauseparam->rx_pause = bnad->bna.enet.pause_config.rx_pause;
514078086f3SRasesh Mody 	pauseparam->tx_pause = bnad->bna.enet.pause_config.tx_pause;
5158b230ed8SRasesh Mody }
5168b230ed8SRasesh Mody 
5178b230ed8SRasesh Mody static int
5188b230ed8SRasesh Mody bnad_set_pauseparam(struct net_device *netdev,
5198b230ed8SRasesh Mody 		    struct ethtool_pauseparam *pauseparam)
5208b230ed8SRasesh Mody {
5218b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5228b230ed8SRasesh Mody 	struct bna_pause_config pause_config;
5238b230ed8SRasesh Mody 	unsigned long flags;
5248b230ed8SRasesh Mody 
5258b230ed8SRasesh Mody 	if (pauseparam->autoneg == AUTONEG_ENABLE)
5268b230ed8SRasesh Mody 		return -EINVAL;
5278b230ed8SRasesh Mody 
5288b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
529078086f3SRasesh Mody 	if (pauseparam->rx_pause != bnad->bna.enet.pause_config.rx_pause ||
530078086f3SRasesh Mody 	    pauseparam->tx_pause != bnad->bna.enet.pause_config.tx_pause) {
5318b230ed8SRasesh Mody 		pause_config.rx_pause = pauseparam->rx_pause;
5328b230ed8SRasesh Mody 		pause_config.tx_pause = pauseparam->tx_pause;
5338b230ed8SRasesh Mody 		spin_lock_irqsave(&bnad->bna_lock, flags);
534078086f3SRasesh Mody 		bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL);
5358b230ed8SRasesh Mody 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
5368b230ed8SRasesh Mody 	}
5378b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
5388b230ed8SRasesh Mody 	return 0;
5398b230ed8SRasesh Mody }
5408b230ed8SRasesh Mody 
5418b230ed8SRasesh Mody static void
5428b230ed8SRasesh Mody bnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string)
5438b230ed8SRasesh Mody {
5448b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5458b230ed8SRasesh Mody 	int i, j, q_num;
546078086f3SRasesh Mody 	u32 bmap;
5478b230ed8SRasesh Mody 
5488b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
5498b230ed8SRasesh Mody 
5508b230ed8SRasesh Mody 	switch (stringset) {
5518b230ed8SRasesh Mody 	case ETH_SS_STATS:
5528b230ed8SRasesh Mody 		for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
5538b230ed8SRasesh Mody 			BUG_ON(!(strlen(bnad_net_stats_strings[i]) <
5548b230ed8SRasesh Mody 				   ETH_GSTRING_LEN));
5558b230ed8SRasesh Mody 			memcpy(string, bnad_net_stats_strings[i],
5568b230ed8SRasesh Mody 			       ETH_GSTRING_LEN);
5578b230ed8SRasesh Mody 			string += ETH_GSTRING_LEN;
5588b230ed8SRasesh Mody 		}
559078086f3SRasesh Mody 		bmap = bna_tx_rid_mask(&bnad->bna);
560078086f3SRasesh Mody 		for (i = 0; bmap; i++) {
5618b230ed8SRasesh Mody 			if (bmap & 1) {
5628b230ed8SRasesh Mody 				sprintf(string, "txf%d_ucast_octets", i);
5638b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5648b230ed8SRasesh Mody 				sprintf(string, "txf%d_ucast", i);
5658b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5668b230ed8SRasesh Mody 				sprintf(string, "txf%d_ucast_vlan", i);
5678b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5688b230ed8SRasesh Mody 				sprintf(string, "txf%d_mcast_octets", i);
5698b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5708b230ed8SRasesh Mody 				sprintf(string, "txf%d_mcast", i);
5718b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5728b230ed8SRasesh Mody 				sprintf(string, "txf%d_mcast_vlan", i);
5738b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5748b230ed8SRasesh Mody 				sprintf(string, "txf%d_bcast_octets", i);
5758b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5768b230ed8SRasesh Mody 				sprintf(string, "txf%d_bcast", i);
5778b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5788b230ed8SRasesh Mody 				sprintf(string, "txf%d_bcast_vlan", i);
5798b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5808b230ed8SRasesh Mody 				sprintf(string, "txf%d_errors", i);
5818b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5828b230ed8SRasesh Mody 				sprintf(string, "txf%d_filter_vlan", i);
5838b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5848b230ed8SRasesh Mody 				sprintf(string, "txf%d_filter_mac_sa", i);
5858b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5868b230ed8SRasesh Mody 			}
5878b230ed8SRasesh Mody 			bmap >>= 1;
5888b230ed8SRasesh Mody 		}
5898b230ed8SRasesh Mody 
590078086f3SRasesh Mody 		bmap = bna_rx_rid_mask(&bnad->bna);
591078086f3SRasesh Mody 		for (i = 0; bmap; i++) {
5928b230ed8SRasesh Mody 			if (bmap & 1) {
5938b230ed8SRasesh Mody 				sprintf(string, "rxf%d_ucast_octets", i);
5948b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5958b230ed8SRasesh Mody 				sprintf(string, "rxf%d_ucast", i);
5968b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5978b230ed8SRasesh Mody 				sprintf(string, "rxf%d_ucast_vlan", i);
5988b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5998b230ed8SRasesh Mody 				sprintf(string, "rxf%d_mcast_octets", i);
6008b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6018b230ed8SRasesh Mody 				sprintf(string, "rxf%d_mcast", i);
6028b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6038b230ed8SRasesh Mody 				sprintf(string, "rxf%d_mcast_vlan", i);
6048b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6058b230ed8SRasesh Mody 				sprintf(string, "rxf%d_bcast_octets", i);
6068b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6078b230ed8SRasesh Mody 				sprintf(string, "rxf%d_bcast", i);
6088b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6098b230ed8SRasesh Mody 				sprintf(string, "rxf%d_bcast_vlan", i);
6108b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6118b230ed8SRasesh Mody 				sprintf(string, "rxf%d_frame_drops", i);
6128b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6138b230ed8SRasesh Mody 			}
6148b230ed8SRasesh Mody 			bmap >>= 1;
6158b230ed8SRasesh Mody 		}
6168b230ed8SRasesh Mody 
6178b230ed8SRasesh Mody 		q_num = 0;
6188b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
6198b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
6208b230ed8SRasesh Mody 				continue;
6218b230ed8SRasesh Mody 			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
6228b230ed8SRasesh Mody 				sprintf(string, "cq%d_producer_index", q_num);
6238b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6248b230ed8SRasesh Mody 				sprintf(string, "cq%d_consumer_index", q_num);
6258b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6268b230ed8SRasesh Mody 				sprintf(string, "cq%d_hw_producer_index",
6278b230ed8SRasesh Mody 					q_num);
6288b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
629a2122d95SRasesh Mody 				sprintf(string, "cq%d_intr", q_num);
630a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
631a2122d95SRasesh Mody 				sprintf(string, "cq%d_poll", q_num);
632a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
633a2122d95SRasesh Mody 				sprintf(string, "cq%d_schedule", q_num);
634a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
635a2122d95SRasesh Mody 				sprintf(string, "cq%d_keep_poll", q_num);
636a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
637a2122d95SRasesh Mody 				sprintf(string, "cq%d_complete", q_num);
638a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
6398b230ed8SRasesh Mody 				q_num++;
6408b230ed8SRasesh Mody 			}
6418b230ed8SRasesh Mody 		}
6428b230ed8SRasesh Mody 
6438b230ed8SRasesh Mody 		q_num = 0;
6448b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
6458b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
6468b230ed8SRasesh Mody 				continue;
6478b230ed8SRasesh Mody 			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
6488b230ed8SRasesh Mody 				sprintf(string, "rxq%d_packets", q_num);
6498b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6508b230ed8SRasesh Mody 				sprintf(string, "rxq%d_bytes", q_num);
6518b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6528b230ed8SRasesh Mody 				sprintf(string, "rxq%d_packets_with_error",
6538b230ed8SRasesh Mody 								q_num);
6548b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6558b230ed8SRasesh Mody 				sprintf(string, "rxq%d_allocbuf_failed", q_num);
6568b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6578b230ed8SRasesh Mody 				sprintf(string, "rxq%d_producer_index", q_num);
6588b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6598b230ed8SRasesh Mody 				sprintf(string, "rxq%d_consumer_index", q_num);
6608b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6618b230ed8SRasesh Mody 				q_num++;
6628b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb &&
6638b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
6648b230ed8SRasesh Mody 					rcb[1] &&
6658b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
6668b230ed8SRasesh Mody 					rcb[1]->rxq) {
6678b230ed8SRasesh Mody 					sprintf(string, "rxq%d_packets", q_num);
6688b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6698b230ed8SRasesh Mody 					sprintf(string, "rxq%d_bytes", q_num);
6708b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6718b230ed8SRasesh Mody 					sprintf(string,
6728b230ed8SRasesh Mody 					"rxq%d_packets_with_error", q_num);
6738b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6748b230ed8SRasesh Mody 					sprintf(string, "rxq%d_allocbuf_failed",
6758b230ed8SRasesh Mody 								q_num);
6768b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6778b230ed8SRasesh Mody 					sprintf(string, "rxq%d_producer_index",
6788b230ed8SRasesh Mody 								q_num);
6798b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6808b230ed8SRasesh Mody 					sprintf(string, "rxq%d_consumer_index",
6818b230ed8SRasesh Mody 								q_num);
6828b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6838b230ed8SRasesh Mody 					q_num++;
6848b230ed8SRasesh Mody 				}
6858b230ed8SRasesh Mody 			}
6868b230ed8SRasesh Mody 		}
6878b230ed8SRasesh Mody 
6888b230ed8SRasesh Mody 		q_num = 0;
6898b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_tx; i++) {
6908b230ed8SRasesh Mody 			if (!bnad->tx_info[i].tx)
6918b230ed8SRasesh Mody 				continue;
6928b230ed8SRasesh Mody 			for (j = 0; j < bnad->num_txq_per_tx; j++) {
6938b230ed8SRasesh Mody 				sprintf(string, "txq%d_packets", q_num);
6948b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6958b230ed8SRasesh Mody 				sprintf(string, "txq%d_bytes", q_num);
6968b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6978b230ed8SRasesh Mody 				sprintf(string, "txq%d_producer_index", q_num);
6988b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6998b230ed8SRasesh Mody 				sprintf(string, "txq%d_consumer_index", q_num);
7008b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
7018b230ed8SRasesh Mody 				sprintf(string, "txq%d_hw_consumer_index",
7028b230ed8SRasesh Mody 									q_num);
7038b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
7048b230ed8SRasesh Mody 				q_num++;
7058b230ed8SRasesh Mody 			}
7068b230ed8SRasesh Mody 		}
7078b230ed8SRasesh Mody 
7088b230ed8SRasesh Mody 		break;
7098b230ed8SRasesh Mody 
7108b230ed8SRasesh Mody 	default:
7118b230ed8SRasesh Mody 		break;
7128b230ed8SRasesh Mody 	}
7138b230ed8SRasesh Mody 
7148b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
7158b230ed8SRasesh Mody }
7168b230ed8SRasesh Mody 
7178b230ed8SRasesh Mody static int
7188b230ed8SRasesh Mody bnad_get_stats_count_locked(struct net_device *netdev)
7198b230ed8SRasesh Mody {
7208b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
721a2122d95SRasesh Mody 	int i, j, count = 0, rxf_active_num = 0, txf_active_num = 0;
722078086f3SRasesh Mody 	u32 bmap;
7238b230ed8SRasesh Mody 
724078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
725078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
7268b230ed8SRasesh Mody 		if (bmap & 1)
7278b230ed8SRasesh Mody 			txf_active_num++;
7288b230ed8SRasesh Mody 		bmap >>= 1;
7298b230ed8SRasesh Mody 	}
730078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
731078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
7328b230ed8SRasesh Mody 		if (bmap & 1)
7338b230ed8SRasesh Mody 			rxf_active_num++;
7348b230ed8SRasesh Mody 		bmap >>= 1;
7358b230ed8SRasesh Mody 	}
7368b230ed8SRasesh Mody 	count = BNAD_ETHTOOL_STATS_NUM +
7378b230ed8SRasesh Mody 		txf_active_num * BNAD_NUM_TXF_COUNTERS +
7388b230ed8SRasesh Mody 		rxf_active_num * BNAD_NUM_RXF_COUNTERS;
7398b230ed8SRasesh Mody 
7408b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7418b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7428b230ed8SRasesh Mody 			continue;
7438b230ed8SRasesh Mody 		count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS;
7448b230ed8SRasesh Mody 		count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS;
7458b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7468b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
7478b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
7488b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
7498b230ed8SRasesh Mody 				count +=  BNAD_NUM_RXQ_COUNTERS;
7508b230ed8SRasesh Mody 	}
7518b230ed8SRasesh Mody 
7528b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
7538b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
7548b230ed8SRasesh Mody 			continue;
7558b230ed8SRasesh Mody 		count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS;
7568b230ed8SRasesh Mody 	}
7578b230ed8SRasesh Mody 	return count;
7588b230ed8SRasesh Mody }
7598b230ed8SRasesh Mody 
7608b230ed8SRasesh Mody static int
7618b230ed8SRasesh Mody bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
7628b230ed8SRasesh Mody {
7638b230ed8SRasesh Mody 	int i, j;
7648b230ed8SRasesh Mody 	struct bna_rcb *rcb = NULL;
7658b230ed8SRasesh Mody 	struct bna_tcb *tcb = NULL;
7668b230ed8SRasesh Mody 
7678b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7688b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7698b230ed8SRasesh Mody 			continue;
7708b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7718b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
7728b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
7738b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) {
7748b230ed8SRasesh Mody 				buf[bi++] = bnad->rx_info[i].rx_ctrl[j].
7758b230ed8SRasesh Mody 						ccb->producer_index;
7768b230ed8SRasesh Mody 				buf[bi++] = 0; /* ccb->consumer_index */
7778b230ed8SRasesh Mody 				buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
7788b230ed8SRasesh Mody 						ccb->hw_producer_index);
779a2122d95SRasesh Mody 
780a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
781a2122d95SRasesh Mody 						rx_ctrl[j].rx_intr_ctr;
782a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
783a2122d95SRasesh Mody 						rx_ctrl[j].rx_poll_ctr;
784a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
785a2122d95SRasesh Mody 						rx_ctrl[j].rx_schedule;
786a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
787a2122d95SRasesh Mody 						rx_ctrl[j].rx_keep_poll;
788a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
789a2122d95SRasesh Mody 						rx_ctrl[j].rx_complete;
7908b230ed8SRasesh Mody 			}
7918b230ed8SRasesh Mody 	}
7928b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7938b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7948b230ed8SRasesh Mody 			continue;
7958b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7968b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb) {
7978b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
7988b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
7998b230ed8SRasesh Mody 					rcb[0]->rxq) {
8008b230ed8SRasesh Mody 					rcb = bnad->rx_info[i].rx_ctrl[j].
8018b230ed8SRasesh Mody 							ccb->rcb[0];
8028b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_packets;
8038b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_bytes;
8048b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8058b230ed8SRasesh Mody 							rx_packets_with_error;
8068b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8078b230ed8SRasesh Mody 							rxbuf_alloc_failed;
8088b230ed8SRasesh Mody 					buf[bi++] = rcb->producer_index;
8098b230ed8SRasesh Mody 					buf[bi++] = rcb->consumer_index;
8108b230ed8SRasesh Mody 				}
8118b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
8128b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
8138b230ed8SRasesh Mody 					rcb[1]->rxq) {
8148b230ed8SRasesh Mody 					rcb = bnad->rx_info[i].rx_ctrl[j].
8158b230ed8SRasesh Mody 								ccb->rcb[1];
8168b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_packets;
8178b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_bytes;
8188b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8198b230ed8SRasesh Mody 							rx_packets_with_error;
8208b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8218b230ed8SRasesh Mody 							rxbuf_alloc_failed;
8228b230ed8SRasesh Mody 					buf[bi++] = rcb->producer_index;
8238b230ed8SRasesh Mody 					buf[bi++] = rcb->consumer_index;
8248b230ed8SRasesh Mody 				}
8258b230ed8SRasesh Mody 			}
8268b230ed8SRasesh Mody 	}
8278b230ed8SRasesh Mody 
8288b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
8298b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
8308b230ed8SRasesh Mody 			continue;
8318b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_txq_per_tx; j++)
8328b230ed8SRasesh Mody 			if (bnad->tx_info[i].tcb[j] &&
8338b230ed8SRasesh Mody 				bnad->tx_info[i].tcb[j]->txq) {
8348b230ed8SRasesh Mody 				tcb = bnad->tx_info[i].tcb[j];
8358b230ed8SRasesh Mody 				buf[bi++] = tcb->txq->tx_packets;
8368b230ed8SRasesh Mody 				buf[bi++] = tcb->txq->tx_bytes;
8378b230ed8SRasesh Mody 				buf[bi++] = tcb->producer_index;
8388b230ed8SRasesh Mody 				buf[bi++] = tcb->consumer_index;
8398b230ed8SRasesh Mody 				buf[bi++] = *(tcb->hw_consumer_index);
8408b230ed8SRasesh Mody 			}
8418b230ed8SRasesh Mody 	}
8428b230ed8SRasesh Mody 
8438b230ed8SRasesh Mody 	return bi;
8448b230ed8SRasesh Mody }
8458b230ed8SRasesh Mody 
8468b230ed8SRasesh Mody static void
8478b230ed8SRasesh Mody bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
8488b230ed8SRasesh Mody 		       u64 *buf)
8498b230ed8SRasesh Mody {
8508b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
8518b230ed8SRasesh Mody 	int i, j, bi;
852250e061eSEric Dumazet 	unsigned long flags;
853250e061eSEric Dumazet 	struct rtnl_link_stats64 *net_stats64;
8548b230ed8SRasesh Mody 	u64 *stats64;
855078086f3SRasesh Mody 	u32 bmap;
8568b230ed8SRasesh Mody 
8578b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
8588b230ed8SRasesh Mody 	if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
8598b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
8608b230ed8SRasesh Mody 		return;
8618b230ed8SRasesh Mody 	}
8628b230ed8SRasesh Mody 
8638b230ed8SRasesh Mody 	/*
8648b230ed8SRasesh Mody 	 * Used bna_lock to sync reads from bna_stats, which is written
8658b230ed8SRasesh Mody 	 * under the same lock
8668b230ed8SRasesh Mody 	 */
8678b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
8688b230ed8SRasesh Mody 	bi = 0;
8698b230ed8SRasesh Mody 	memset(buf, 0, stats->n_stats * sizeof(u64));
8708b230ed8SRasesh Mody 
871250e061eSEric Dumazet 	net_stats64 = (struct rtnl_link_stats64 *)buf;
872250e061eSEric Dumazet 	bnad_netdev_qstats_fill(bnad, net_stats64);
873250e061eSEric Dumazet 	bnad_netdev_hwstats_fill(bnad, net_stats64);
8748b230ed8SRasesh Mody 
875250e061eSEric Dumazet 	bi = sizeof(*net_stats64) / sizeof(u64);
8768b230ed8SRasesh Mody 
877f7c0fa4cSRasesh Mody 	/* Get netif_queue_stopped from stack */
878f7c0fa4cSRasesh Mody 	bnad->stats.drv_stats.netif_queue_stopped = netif_queue_stopped(netdev);
879f7c0fa4cSRasesh Mody 
8808b230ed8SRasesh Mody 	/* Fill driver stats into ethtool buffers */
8818b230ed8SRasesh Mody 	stats64 = (u64 *)&bnad->stats.drv_stats;
8828b230ed8SRasesh Mody 	for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
8838b230ed8SRasesh Mody 		buf[bi++] = stats64[i];
8848b230ed8SRasesh Mody 
8858b230ed8SRasesh Mody 	/* Fill hardware stats excluding the rxf/txf into ethtool bufs */
886078086f3SRasesh Mody 	stats64 = (u64 *) &bnad->stats.bna_stats->hw_stats;
8878b230ed8SRasesh Mody 	for (i = 0;
888078086f3SRasesh Mody 	     i < offsetof(struct bfi_enet_stats, rxf_stats[0]) /
889078086f3SRasesh Mody 		sizeof(u64);
8908b230ed8SRasesh Mody 	     i++)
8918b230ed8SRasesh Mody 		buf[bi++] = stats64[i];
8928b230ed8SRasesh Mody 
8938b230ed8SRasesh Mody 	/* Fill txf stats into ethtool buffers */
894078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
895078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
8968b230ed8SRasesh Mody 		if (bmap & 1) {
8978b230ed8SRasesh Mody 			stats64 = (u64 *)&bnad->stats.bna_stats->
898078086f3SRasesh Mody 						hw_stats.txf_stats[i];
899078086f3SRasesh Mody 			for (j = 0; j < sizeof(struct bfi_enet_stats_txf) /
9008b230ed8SRasesh Mody 					sizeof(u64); j++)
9018b230ed8SRasesh Mody 				buf[bi++] = stats64[j];
9028b230ed8SRasesh Mody 		}
9038b230ed8SRasesh Mody 		bmap >>= 1;
9048b230ed8SRasesh Mody 	}
9058b230ed8SRasesh Mody 
9068b230ed8SRasesh Mody 	/*  Fill rxf stats into ethtool buffers */
907078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
908078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
9098b230ed8SRasesh Mody 		if (bmap & 1) {
9108b230ed8SRasesh Mody 			stats64 = (u64 *)&bnad->stats.bna_stats->
911078086f3SRasesh Mody 						hw_stats.rxf_stats[i];
912078086f3SRasesh Mody 			for (j = 0; j < sizeof(struct bfi_enet_stats_rxf) /
9138b230ed8SRasesh Mody 					sizeof(u64); j++)
9148b230ed8SRasesh Mody 				buf[bi++] = stats64[j];
9158b230ed8SRasesh Mody 		}
9168b230ed8SRasesh Mody 		bmap >>= 1;
9178b230ed8SRasesh Mody 	}
9188b230ed8SRasesh Mody 
9198b230ed8SRasesh Mody 	/* Fill per Q stats into ethtool buffers */
9208b230ed8SRasesh Mody 	bi = bnad_per_q_stats_fill(bnad, buf, bi);
9218b230ed8SRasesh Mody 
9228b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
9238b230ed8SRasesh Mody 
9248b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
9258b230ed8SRasesh Mody }
9268b230ed8SRasesh Mody 
9278b230ed8SRasesh Mody static int
9288b230ed8SRasesh Mody bnad_get_sset_count(struct net_device *netdev, int sset)
9298b230ed8SRasesh Mody {
9308b230ed8SRasesh Mody 	switch (sset) {
9318b230ed8SRasesh Mody 	case ETH_SS_STATS:
9328b230ed8SRasesh Mody 		return bnad_get_stats_count_locked(netdev);
9338b230ed8SRasesh Mody 	default:
9348b230ed8SRasesh Mody 		return -EOPNOTSUPP;
9358b230ed8SRasesh Mody 	}
9368b230ed8SRasesh Mody }
9378b230ed8SRasesh Mody 
93872a9730bSKrishna Gudipati static u32
93972a9730bSKrishna Gudipati bnad_get_flash_partition_by_offset(struct bnad *bnad, u32 offset,
94072a9730bSKrishna Gudipati 				u32 *base_offset)
94172a9730bSKrishna Gudipati {
94272a9730bSKrishna Gudipati 	struct bfa_flash_attr *flash_attr;
94372a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
94472a9730bSKrishna Gudipati 	u32 i, flash_part = 0, ret;
94572a9730bSKrishna Gudipati 	unsigned long flags = 0;
94672a9730bSKrishna Gudipati 
94772a9730bSKrishna Gudipati 	flash_attr = kzalloc(sizeof(struct bfa_flash_attr), GFP_KERNEL);
94872a9730bSKrishna Gudipati 	if (!flash_attr)
949027a3b61SDan Carpenter 		return 0;
95072a9730bSKrishna Gudipati 
95172a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
95272a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
95372a9730bSKrishna Gudipati 
95472a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
95572a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
95672a9730bSKrishna Gudipati 	ret = bfa_nw_flash_get_attr(&bnad->bna.flash, flash_attr,
95772a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
95872a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
95972a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
96072a9730bSKrishna Gudipati 		kfree(flash_attr);
961027a3b61SDan Carpenter 		return 0;
96272a9730bSKrishna Gudipati 	}
96372a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
96472a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
96572a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
96672a9730bSKrishna Gudipati 
96772a9730bSKrishna Gudipati 	/* Check for the flash type & base offset value */
96872a9730bSKrishna Gudipati 	if (ret == BFA_STATUS_OK) {
96972a9730bSKrishna Gudipati 		for (i = 0; i < flash_attr->npart; i++) {
97072a9730bSKrishna Gudipati 			if (offset >= flash_attr->part[i].part_off &&
97172a9730bSKrishna Gudipati 			    offset < (flash_attr->part[i].part_off +
97272a9730bSKrishna Gudipati 				      flash_attr->part[i].part_size)) {
97372a9730bSKrishna Gudipati 				flash_part = flash_attr->part[i].part_type;
97472a9730bSKrishna Gudipati 				*base_offset = flash_attr->part[i].part_off;
97572a9730bSKrishna Gudipati 				break;
97672a9730bSKrishna Gudipati 			}
97772a9730bSKrishna Gudipati 		}
97872a9730bSKrishna Gudipati 	}
97972a9730bSKrishna Gudipati 	kfree(flash_attr);
98072a9730bSKrishna Gudipati 	return flash_part;
98172a9730bSKrishna Gudipati }
98272a9730bSKrishna Gudipati 
98372a9730bSKrishna Gudipati static int
98472a9730bSKrishna Gudipati bnad_get_eeprom_len(struct net_device *netdev)
98572a9730bSKrishna Gudipati {
98672a9730bSKrishna Gudipati 	return BFA_TOTAL_FLASH_SIZE;
98772a9730bSKrishna Gudipati }
98872a9730bSKrishna Gudipati 
98972a9730bSKrishna Gudipati static int
99072a9730bSKrishna Gudipati bnad_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
99172a9730bSKrishna Gudipati 		u8 *bytes)
99272a9730bSKrishna Gudipati {
99372a9730bSKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
99472a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
99572a9730bSKrishna Gudipati 	u32 flash_part = 0, base_offset = 0;
99672a9730bSKrishna Gudipati 	unsigned long flags = 0;
99772a9730bSKrishna Gudipati 	int ret = 0;
99872a9730bSKrishna Gudipati 
99972a9730bSKrishna Gudipati 	/* Check if the flash read request is valid */
100072a9730bSKrishna Gudipati 	if (eeprom->magic != (bnad->pcidev->vendor |
100172a9730bSKrishna Gudipati 			     (bnad->pcidev->device << 16)))
100272a9730bSKrishna Gudipati 		return -EFAULT;
100372a9730bSKrishna Gudipati 
100472a9730bSKrishna Gudipati 	/* Query the flash partition based on the offset */
100572a9730bSKrishna Gudipati 	flash_part = bnad_get_flash_partition_by_offset(bnad,
100672a9730bSKrishna Gudipati 				eeprom->offset, &base_offset);
1007027a3b61SDan Carpenter 	if (flash_part == 0)
100872a9730bSKrishna Gudipati 		return -EFAULT;
100972a9730bSKrishna Gudipati 
101072a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
101172a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
101272a9730bSKrishna Gudipati 
101372a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
101472a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
101572a9730bSKrishna Gudipati 	ret = bfa_nw_flash_read_part(&bnad->bna.flash, flash_part,
101672a9730bSKrishna Gudipati 				bnad->id, bytes, eeprom->len,
101772a9730bSKrishna Gudipati 				eeprom->offset - base_offset,
101872a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
101972a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
102072a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
102172a9730bSKrishna Gudipati 		goto done;
102272a9730bSKrishna Gudipati 	}
102372a9730bSKrishna Gudipati 
102472a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
102572a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
102672a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
102772a9730bSKrishna Gudipati done:
102872a9730bSKrishna Gudipati 	return ret;
102972a9730bSKrishna Gudipati }
103072a9730bSKrishna Gudipati 
103172a9730bSKrishna Gudipati static int
103272a9730bSKrishna Gudipati bnad_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
103372a9730bSKrishna Gudipati 		u8 *bytes)
103472a9730bSKrishna Gudipati {
103572a9730bSKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
103672a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
103772a9730bSKrishna Gudipati 	u32 flash_part = 0, base_offset = 0;
103872a9730bSKrishna Gudipati 	unsigned long flags = 0;
103972a9730bSKrishna Gudipati 	int ret = 0;
104072a9730bSKrishna Gudipati 
104172a9730bSKrishna Gudipati 	/* Check if the flash update request is valid */
104272a9730bSKrishna Gudipati 	if (eeprom->magic != (bnad->pcidev->vendor |
104372a9730bSKrishna Gudipati 			     (bnad->pcidev->device << 16)))
104472a9730bSKrishna Gudipati 		return -EINVAL;
104572a9730bSKrishna Gudipati 
104672a9730bSKrishna Gudipati 	/* Query the flash partition based on the offset */
104772a9730bSKrishna Gudipati 	flash_part = bnad_get_flash_partition_by_offset(bnad,
104872a9730bSKrishna Gudipati 				eeprom->offset, &base_offset);
1049027a3b61SDan Carpenter 	if (flash_part == 0)
105072a9730bSKrishna Gudipati 		return -EFAULT;
105172a9730bSKrishna Gudipati 
105272a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
105372a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
105472a9730bSKrishna Gudipati 
105572a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
105672a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
105772a9730bSKrishna Gudipati 	ret = bfa_nw_flash_update_part(&bnad->bna.flash, flash_part,
105872a9730bSKrishna Gudipati 				bnad->id, bytes, eeprom->len,
105972a9730bSKrishna Gudipati 				eeprom->offset - base_offset,
106072a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
106172a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
106272a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
106372a9730bSKrishna Gudipati 		goto done;
106472a9730bSKrishna Gudipati 	}
106572a9730bSKrishna Gudipati 
106672a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
106772a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
106872a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
106972a9730bSKrishna Gudipati done:
107072a9730bSKrishna Gudipati 	return ret;
107172a9730bSKrishna Gudipati }
107272a9730bSKrishna Gudipati 
107357b9bef0SKrishna Gudipati static int
107457b9bef0SKrishna Gudipati bnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash)
107557b9bef0SKrishna Gudipati {
107657b9bef0SKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
107757b9bef0SKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
107857b9bef0SKrishna Gudipati 	const struct firmware *fw;
107957b9bef0SKrishna Gudipati 	int ret = 0;
108057b9bef0SKrishna Gudipati 
108157b9bef0SKrishna Gudipati 	ret = request_firmware(&fw, eflash->data, &bnad->pcidev->dev);
108257b9bef0SKrishna Gudipati 	if (ret) {
108357b9bef0SKrishna Gudipati 		pr_err("BNA: Can't locate firmware %s\n", eflash->data);
108457b9bef0SKrishna Gudipati 		goto out;
108557b9bef0SKrishna Gudipati 	}
108657b9bef0SKrishna Gudipati 
108757b9bef0SKrishna Gudipati 	fcomp.bnad = bnad;
108857b9bef0SKrishna Gudipati 	fcomp.comp_status = 0;
108957b9bef0SKrishna Gudipati 
109057b9bef0SKrishna Gudipati 	init_completion(&fcomp.comp);
109157b9bef0SKrishna Gudipati 	spin_lock_irq(&bnad->bna_lock);
109257b9bef0SKrishna Gudipati 	ret = bfa_nw_flash_update_part(&bnad->bna.flash, BFA_FLASH_PART_FWIMG,
109357b9bef0SKrishna Gudipati 				bnad->id, (u8 *)fw->data, fw->size, 0,
109457b9bef0SKrishna Gudipati 				bnad_cb_completion, &fcomp);
109557b9bef0SKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
109657b9bef0SKrishna Gudipati 		pr_warn("BNA: Flash update failed with err: %d\n", ret);
109757b9bef0SKrishna Gudipati 		ret = -EIO;
109857b9bef0SKrishna Gudipati 		spin_unlock_irq(&bnad->bna_lock);
109957b9bef0SKrishna Gudipati 		goto out;
110057b9bef0SKrishna Gudipati 	}
110157b9bef0SKrishna Gudipati 
110257b9bef0SKrishna Gudipati 	spin_unlock_irq(&bnad->bna_lock);
110357b9bef0SKrishna Gudipati 	wait_for_completion(&fcomp.comp);
110457b9bef0SKrishna Gudipati 	if (fcomp.comp_status != BFA_STATUS_OK) {
110557b9bef0SKrishna Gudipati 		ret = -EIO;
110657b9bef0SKrishna Gudipati 		pr_warn("BNA: Firmware image update to flash failed with: %d\n",
110757b9bef0SKrishna Gudipati 			fcomp.comp_status);
110857b9bef0SKrishna Gudipati 	}
110957b9bef0SKrishna Gudipati out:
111057b9bef0SKrishna Gudipati 	release_firmware(fw);
111157b9bef0SKrishna Gudipati 	return ret;
111257b9bef0SKrishna Gudipati }
111357b9bef0SKrishna Gudipati 
1114975419cfSstephen hemminger static const struct ethtool_ops bnad_ethtool_ops = {
11158b230ed8SRasesh Mody 	.get_settings = bnad_get_settings,
11168b230ed8SRasesh Mody 	.set_settings = bnad_set_settings,
11178b230ed8SRasesh Mody 	.get_drvinfo = bnad_get_drvinfo,
11188b230ed8SRasesh Mody 	.get_wol = bnad_get_wol,
11198b230ed8SRasesh Mody 	.get_link = ethtool_op_get_link,
11208b230ed8SRasesh Mody 	.get_coalesce = bnad_get_coalesce,
11218b230ed8SRasesh Mody 	.set_coalesce = bnad_set_coalesce,
11228b230ed8SRasesh Mody 	.get_ringparam = bnad_get_ringparam,
11238b230ed8SRasesh Mody 	.set_ringparam = bnad_set_ringparam,
11248b230ed8SRasesh Mody 	.get_pauseparam = bnad_get_pauseparam,
11258b230ed8SRasesh Mody 	.set_pauseparam = bnad_set_pauseparam,
11268b230ed8SRasesh Mody 	.get_strings = bnad_get_strings,
11278b230ed8SRasesh Mody 	.get_ethtool_stats = bnad_get_ethtool_stats,
112872a9730bSKrishna Gudipati 	.get_sset_count = bnad_get_sset_count,
112972a9730bSKrishna Gudipati 	.get_eeprom_len = bnad_get_eeprom_len,
113072a9730bSKrishna Gudipati 	.get_eeprom = bnad_get_eeprom,
113172a9730bSKrishna Gudipati 	.set_eeprom = bnad_set_eeprom,
113257b9bef0SKrishna Gudipati 	.flash_device = bnad_flash_device,
11338b230ed8SRasesh Mody };
11348b230ed8SRasesh Mody 
11358b230ed8SRasesh Mody void
11368b230ed8SRasesh Mody bnad_set_ethtool_ops(struct net_device *netdev)
11378b230ed8SRasesh Mody {
11388b230ed8SRasesh Mody 	SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
11398b230ed8SRasesh Mody }
1140