xref: /linux/drivers/net/ethernet/brocade/bna/bnad_ethtool.c (revision fee1253e280a6114688958f4762a838d4d9bc306)
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 
105478ab8c9SRasesh Mody 	"mac_stats_clr_cnt",
1068b230ed8SRasesh Mody 	"mac_frame_64",
1078b230ed8SRasesh Mody 	"mac_frame_65_127",
1088b230ed8SRasesh Mody 	"mac_frame_128_255",
1098b230ed8SRasesh Mody 	"mac_frame_256_511",
1108b230ed8SRasesh Mody 	"mac_frame_512_1023",
1118b230ed8SRasesh Mody 	"mac_frame_1024_1518",
1128b230ed8SRasesh Mody 	"mac_frame_1518_1522",
1138b230ed8SRasesh Mody 	"mac_rx_bytes",
1148b230ed8SRasesh Mody 	"mac_rx_packets",
1158b230ed8SRasesh Mody 	"mac_rx_fcs_error",
1168b230ed8SRasesh Mody 	"mac_rx_multicast",
1178b230ed8SRasesh Mody 	"mac_rx_broadcast",
1188b230ed8SRasesh Mody 	"mac_rx_control_frames",
1198b230ed8SRasesh Mody 	"mac_rx_pause",
1208b230ed8SRasesh Mody 	"mac_rx_unknown_opcode",
1218b230ed8SRasesh Mody 	"mac_rx_alignment_error",
1228b230ed8SRasesh Mody 	"mac_rx_frame_length_error",
1238b230ed8SRasesh Mody 	"mac_rx_code_error",
1248b230ed8SRasesh Mody 	"mac_rx_carrier_sense_error",
1258b230ed8SRasesh Mody 	"mac_rx_undersize",
1268b230ed8SRasesh Mody 	"mac_rx_oversize",
1278b230ed8SRasesh Mody 	"mac_rx_fragments",
1288b230ed8SRasesh Mody 	"mac_rx_jabber",
1298b230ed8SRasesh Mody 	"mac_rx_drop",
1308b230ed8SRasesh Mody 
1318b230ed8SRasesh Mody 	"mac_tx_bytes",
1328b230ed8SRasesh Mody 	"mac_tx_packets",
1338b230ed8SRasesh Mody 	"mac_tx_multicast",
1348b230ed8SRasesh Mody 	"mac_tx_broadcast",
1358b230ed8SRasesh Mody 	"mac_tx_pause",
1368b230ed8SRasesh Mody 	"mac_tx_deferral",
1378b230ed8SRasesh Mody 	"mac_tx_excessive_deferral",
1388b230ed8SRasesh Mody 	"mac_tx_single_collision",
1398b230ed8SRasesh Mody 	"mac_tx_muliple_collision",
1408b230ed8SRasesh Mody 	"mac_tx_late_collision",
1418b230ed8SRasesh Mody 	"mac_tx_excessive_collision",
1428b230ed8SRasesh Mody 	"mac_tx_total_collision",
1438b230ed8SRasesh Mody 	"mac_tx_pause_honored",
1448b230ed8SRasesh Mody 	"mac_tx_drop",
1458b230ed8SRasesh Mody 	"mac_tx_jabber",
1468b230ed8SRasesh Mody 	"mac_tx_fcs_error",
1478b230ed8SRasesh Mody 	"mac_tx_control_frame",
1488b230ed8SRasesh Mody 	"mac_tx_oversize",
1498b230ed8SRasesh Mody 	"mac_tx_undersize",
1508b230ed8SRasesh Mody 	"mac_tx_fragments",
1518b230ed8SRasesh Mody 
1528b230ed8SRasesh Mody 	"bpc_tx_pause_0",
1538b230ed8SRasesh Mody 	"bpc_tx_pause_1",
1548b230ed8SRasesh Mody 	"bpc_tx_pause_2",
1558b230ed8SRasesh Mody 	"bpc_tx_pause_3",
1568b230ed8SRasesh Mody 	"bpc_tx_pause_4",
1578b230ed8SRasesh Mody 	"bpc_tx_pause_5",
1588b230ed8SRasesh Mody 	"bpc_tx_pause_6",
1598b230ed8SRasesh Mody 	"bpc_tx_pause_7",
1608b230ed8SRasesh Mody 	"bpc_tx_zero_pause_0",
1618b230ed8SRasesh Mody 	"bpc_tx_zero_pause_1",
1628b230ed8SRasesh Mody 	"bpc_tx_zero_pause_2",
1638b230ed8SRasesh Mody 	"bpc_tx_zero_pause_3",
1648b230ed8SRasesh Mody 	"bpc_tx_zero_pause_4",
1658b230ed8SRasesh Mody 	"bpc_tx_zero_pause_5",
1668b230ed8SRasesh Mody 	"bpc_tx_zero_pause_6",
1678b230ed8SRasesh Mody 	"bpc_tx_zero_pause_7",
1688b230ed8SRasesh Mody 	"bpc_tx_first_pause_0",
1698b230ed8SRasesh Mody 	"bpc_tx_first_pause_1",
1708b230ed8SRasesh Mody 	"bpc_tx_first_pause_2",
1718b230ed8SRasesh Mody 	"bpc_tx_first_pause_3",
1728b230ed8SRasesh Mody 	"bpc_tx_first_pause_4",
1738b230ed8SRasesh Mody 	"bpc_tx_first_pause_5",
1748b230ed8SRasesh Mody 	"bpc_tx_first_pause_6",
1758b230ed8SRasesh Mody 	"bpc_tx_first_pause_7",
1768b230ed8SRasesh Mody 
1778b230ed8SRasesh Mody 	"bpc_rx_pause_0",
1788b230ed8SRasesh Mody 	"bpc_rx_pause_1",
1798b230ed8SRasesh Mody 	"bpc_rx_pause_2",
1808b230ed8SRasesh Mody 	"bpc_rx_pause_3",
1818b230ed8SRasesh Mody 	"bpc_rx_pause_4",
1828b230ed8SRasesh Mody 	"bpc_rx_pause_5",
1838b230ed8SRasesh Mody 	"bpc_rx_pause_6",
1848b230ed8SRasesh Mody 	"bpc_rx_pause_7",
1858b230ed8SRasesh Mody 	"bpc_rx_zero_pause_0",
1868b230ed8SRasesh Mody 	"bpc_rx_zero_pause_1",
1878b230ed8SRasesh Mody 	"bpc_rx_zero_pause_2",
1888b230ed8SRasesh Mody 	"bpc_rx_zero_pause_3",
1898b230ed8SRasesh Mody 	"bpc_rx_zero_pause_4",
1908b230ed8SRasesh Mody 	"bpc_rx_zero_pause_5",
1918b230ed8SRasesh Mody 	"bpc_rx_zero_pause_6",
1928b230ed8SRasesh Mody 	"bpc_rx_zero_pause_7",
1938b230ed8SRasesh Mody 	"bpc_rx_first_pause_0",
1948b230ed8SRasesh Mody 	"bpc_rx_first_pause_1",
1958b230ed8SRasesh Mody 	"bpc_rx_first_pause_2",
1968b230ed8SRasesh Mody 	"bpc_rx_first_pause_3",
1978b230ed8SRasesh Mody 	"bpc_rx_first_pause_4",
1988b230ed8SRasesh Mody 	"bpc_rx_first_pause_5",
1998b230ed8SRasesh Mody 	"bpc_rx_first_pause_6",
2008b230ed8SRasesh Mody 	"bpc_rx_first_pause_7",
2018b230ed8SRasesh Mody 
2028b230ed8SRasesh Mody 	"rad_rx_frames",
2038b230ed8SRasesh Mody 	"rad_rx_octets",
2048b230ed8SRasesh Mody 	"rad_rx_vlan_frames",
2058b230ed8SRasesh Mody 	"rad_rx_ucast",
2068b230ed8SRasesh Mody 	"rad_rx_ucast_octets",
2078b230ed8SRasesh Mody 	"rad_rx_ucast_vlan",
2088b230ed8SRasesh Mody 	"rad_rx_mcast",
2098b230ed8SRasesh Mody 	"rad_rx_mcast_octets",
2108b230ed8SRasesh Mody 	"rad_rx_mcast_vlan",
2118b230ed8SRasesh Mody 	"rad_rx_bcast",
2128b230ed8SRasesh Mody 	"rad_rx_bcast_octets",
2138b230ed8SRasesh Mody 	"rad_rx_bcast_vlan",
2148b230ed8SRasesh Mody 	"rad_rx_drops",
2158b230ed8SRasesh Mody 
216a2122d95SRasesh Mody 	"rlb_rad_rx_frames",
217a2122d95SRasesh Mody 	"rlb_rad_rx_octets",
218a2122d95SRasesh Mody 	"rlb_rad_rx_vlan_frames",
219a2122d95SRasesh Mody 	"rlb_rad_rx_ucast",
220a2122d95SRasesh Mody 	"rlb_rad_rx_ucast_octets",
221a2122d95SRasesh Mody 	"rlb_rad_rx_ucast_vlan",
222a2122d95SRasesh Mody 	"rlb_rad_rx_mcast",
223a2122d95SRasesh Mody 	"rlb_rad_rx_mcast_octets",
224a2122d95SRasesh Mody 	"rlb_rad_rx_mcast_vlan",
225a2122d95SRasesh Mody 	"rlb_rad_rx_bcast",
226a2122d95SRasesh Mody 	"rlb_rad_rx_bcast_octets",
227a2122d95SRasesh Mody 	"rlb_rad_rx_bcast_vlan",
228a2122d95SRasesh Mody 	"rlb_rad_rx_drops",
229a2122d95SRasesh Mody 
2308b230ed8SRasesh Mody 	"fc_rx_ucast_octets",
2318b230ed8SRasesh Mody 	"fc_rx_ucast",
2328b230ed8SRasesh Mody 	"fc_rx_ucast_vlan",
2338b230ed8SRasesh Mody 	"fc_rx_mcast_octets",
2348b230ed8SRasesh Mody 	"fc_rx_mcast",
2358b230ed8SRasesh Mody 	"fc_rx_mcast_vlan",
2368b230ed8SRasesh Mody 	"fc_rx_bcast_octets",
2378b230ed8SRasesh Mody 	"fc_rx_bcast",
2388b230ed8SRasesh Mody 	"fc_rx_bcast_vlan",
2398b230ed8SRasesh Mody 
2408b230ed8SRasesh Mody 	"fc_tx_ucast_octets",
2418b230ed8SRasesh Mody 	"fc_tx_ucast",
2428b230ed8SRasesh Mody 	"fc_tx_ucast_vlan",
2438b230ed8SRasesh Mody 	"fc_tx_mcast_octets",
2448b230ed8SRasesh Mody 	"fc_tx_mcast",
2458b230ed8SRasesh Mody 	"fc_tx_mcast_vlan",
2468b230ed8SRasesh Mody 	"fc_tx_bcast_octets",
2478b230ed8SRasesh Mody 	"fc_tx_bcast",
2488b230ed8SRasesh Mody 	"fc_tx_bcast_vlan",
2498b230ed8SRasesh Mody 	"fc_tx_parity_errors",
2508b230ed8SRasesh Mody 	"fc_tx_timeout",
2518b230ed8SRasesh Mody 	"fc_tx_fid_parity_errors",
2528b230ed8SRasesh Mody };
2538b230ed8SRasesh Mody 
2548b230ed8SRasesh Mody static int
2558b230ed8SRasesh Mody bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
2568b230ed8SRasesh Mody {
2578b230ed8SRasesh Mody 	cmd->supported = SUPPORTED_10000baseT_Full;
2588b230ed8SRasesh Mody 	cmd->advertising = ADVERTISED_10000baseT_Full;
2598b230ed8SRasesh Mody 	cmd->autoneg = AUTONEG_DISABLE;
2608b230ed8SRasesh Mody 	cmd->supported |= SUPPORTED_FIBRE;
2618b230ed8SRasesh Mody 	cmd->advertising |= ADVERTISED_FIBRE;
2628b230ed8SRasesh Mody 	cmd->port = PORT_FIBRE;
2638b230ed8SRasesh Mody 	cmd->phy_address = 0;
2648b230ed8SRasesh Mody 
2658b230ed8SRasesh Mody 	if (netif_carrier_ok(netdev)) {
26670739497SDavid Decotigny 		ethtool_cmd_speed_set(cmd, SPEED_10000);
2678b230ed8SRasesh Mody 		cmd->duplex = DUPLEX_FULL;
2688b230ed8SRasesh Mody 	} else {
26970739497SDavid Decotigny 		ethtool_cmd_speed_set(cmd, -1);
2708b230ed8SRasesh Mody 		cmd->duplex = -1;
2718b230ed8SRasesh Mody 	}
2728b230ed8SRasesh Mody 	cmd->transceiver = XCVR_EXTERNAL;
2738b230ed8SRasesh Mody 	cmd->maxtxpkt = 0;
2748b230ed8SRasesh Mody 	cmd->maxrxpkt = 0;
2758b230ed8SRasesh Mody 
2768b230ed8SRasesh Mody 	return 0;
2778b230ed8SRasesh Mody }
2788b230ed8SRasesh Mody 
2798b230ed8SRasesh Mody static int
2808b230ed8SRasesh Mody bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
2818b230ed8SRasesh Mody {
2828b230ed8SRasesh Mody 	/* 10G full duplex setting supported only */
2838b230ed8SRasesh Mody 	if (cmd->autoneg == AUTONEG_ENABLE)
2848b230ed8SRasesh Mody 		return -EOPNOTSUPP; else {
28525db0338SDavid Decotigny 		if ((ethtool_cmd_speed(cmd) == SPEED_10000)
28625db0338SDavid Decotigny 		    && (cmd->duplex == DUPLEX_FULL))
2878b230ed8SRasesh Mody 			return 0;
2888b230ed8SRasesh Mody 	}
2898b230ed8SRasesh Mody 
2908b230ed8SRasesh Mody 	return -EOPNOTSUPP;
2918b230ed8SRasesh Mody }
2928b230ed8SRasesh Mody 
2938b230ed8SRasesh Mody static void
2948b230ed8SRasesh Mody bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
2958b230ed8SRasesh Mody {
2968b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
2978b230ed8SRasesh Mody 	struct bfa_ioc_attr *ioc_attr;
2988b230ed8SRasesh Mody 	unsigned long flags;
2998b230ed8SRasesh Mody 
30068aad78cSRick Jones 	strlcpy(drvinfo->driver, BNAD_NAME, sizeof(drvinfo->driver));
30168aad78cSRick Jones 	strlcpy(drvinfo->version, BNAD_VERSION, sizeof(drvinfo->version));
3028b230ed8SRasesh Mody 
3038b230ed8SRasesh Mody 	ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
3048b230ed8SRasesh Mody 	if (ioc_attr) {
3058b230ed8SRasesh Mody 		spin_lock_irqsave(&bnad->bna_lock, flags);
306078086f3SRasesh Mody 		bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr);
3078b230ed8SRasesh Mody 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
3088b230ed8SRasesh Mody 
30968aad78cSRick Jones 		strlcpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
31068aad78cSRick Jones 			sizeof(drvinfo->fw_version));
3118b230ed8SRasesh Mody 		kfree(ioc_attr);
3128b230ed8SRasesh Mody 	}
3138b230ed8SRasesh Mody 
31468aad78cSRick Jones 	strlcpy(drvinfo->bus_info, pci_name(bnad->pcidev),
31568aad78cSRick Jones 		sizeof(drvinfo->bus_info));
3168b230ed8SRasesh Mody }
3178b230ed8SRasesh Mody 
3188b230ed8SRasesh Mody static void
3198b230ed8SRasesh Mody bnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo)
3208b230ed8SRasesh Mody {
3218b230ed8SRasesh Mody 	wolinfo->supported = 0;
3228b230ed8SRasesh Mody 	wolinfo->wolopts = 0;
3238b230ed8SRasesh Mody }
3248b230ed8SRasesh Mody 
3258b230ed8SRasesh Mody static int
3268b230ed8SRasesh Mody bnad_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
3278b230ed8SRasesh Mody {
3288b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
3298b230ed8SRasesh Mody 	unsigned long flags;
3308b230ed8SRasesh Mody 
3318b230ed8SRasesh Mody 	/* Lock rqd. to access bnad->bna_lock */
3328b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
3338b230ed8SRasesh Mody 	coalesce->use_adaptive_rx_coalesce =
3348b230ed8SRasesh Mody 		(bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false;
3358b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
3368b230ed8SRasesh Mody 
3378b230ed8SRasesh Mody 	coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
3388b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT;
3398b230ed8SRasesh Mody 	coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
3408b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT;
3418b230ed8SRasesh Mody 	coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT;
3428b230ed8SRasesh Mody 
3438b230ed8SRasesh Mody 	return 0;
3448b230ed8SRasesh Mody }
3458b230ed8SRasesh Mody 
3468b230ed8SRasesh Mody static int
3478b230ed8SRasesh Mody bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
3488b230ed8SRasesh Mody {
3498b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
3508b230ed8SRasesh Mody 	unsigned long flags;
351a2122d95SRasesh Mody 	int to_del = 0;
3528b230ed8SRasesh Mody 
3538b230ed8SRasesh Mody 	if (coalesce->rx_coalesce_usecs == 0 ||
3548b230ed8SRasesh Mody 	    coalesce->rx_coalesce_usecs >
3558b230ed8SRasesh Mody 	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
3568b230ed8SRasesh Mody 		return -EINVAL;
3578b230ed8SRasesh Mody 
3588b230ed8SRasesh Mody 	if (coalesce->tx_coalesce_usecs == 0 ||
3598b230ed8SRasesh Mody 	    coalesce->tx_coalesce_usecs >
3608b230ed8SRasesh Mody 	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
3618b230ed8SRasesh Mody 		return -EINVAL;
3628b230ed8SRasesh Mody 
3638b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
3648b230ed8SRasesh Mody 	/*
3658b230ed8SRasesh Mody 	 * Do not need to store rx_coalesce_usecs here
3668b230ed8SRasesh Mody 	 * Every time DIM is disabled, we can get it from the
3678b230ed8SRasesh Mody 	 * stack.
3688b230ed8SRasesh Mody 	 */
3698b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
3708b230ed8SRasesh Mody 	if (coalesce->use_adaptive_rx_coalesce) {
3718b230ed8SRasesh Mody 		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) {
3728b230ed8SRasesh Mody 			bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
3738b230ed8SRasesh Mody 			bnad_dim_timer_start(bnad);
3748b230ed8SRasesh Mody 		}
3758b230ed8SRasesh Mody 	} else {
3768b230ed8SRasesh Mody 		if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) {
3778b230ed8SRasesh Mody 			bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED;
378a2122d95SRasesh Mody 			if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
379a2122d95SRasesh Mody 			    test_bit(BNAD_RF_DIM_TIMER_RUNNING,
380a2122d95SRasesh Mody 			    &bnad->run_flags)) {
3818b230ed8SRasesh Mody 				clear_bit(BNAD_RF_DIM_TIMER_RUNNING,
3828b230ed8SRasesh Mody 							&bnad->run_flags);
383a2122d95SRasesh Mody 				to_del = 1;
384a2122d95SRasesh Mody 			}
3858b230ed8SRasesh Mody 			spin_unlock_irqrestore(&bnad->bna_lock, flags);
386a2122d95SRasesh Mody 			if (to_del)
3878b230ed8SRasesh Mody 				del_timer_sync(&bnad->dim_timer);
3888b230ed8SRasesh Mody 			spin_lock_irqsave(&bnad->bna_lock, flags);
3898b230ed8SRasesh Mody 			bnad_rx_coalescing_timeo_set(bnad);
3908b230ed8SRasesh Mody 		}
3918b230ed8SRasesh Mody 	}
3928b230ed8SRasesh Mody 	if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs /
3938b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT) {
3948b230ed8SRasesh Mody 		bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
3958b230ed8SRasesh Mody 						BFI_COALESCING_TIMER_UNIT;
3968b230ed8SRasesh Mody 		bnad_tx_coalescing_timeo_set(bnad);
3978b230ed8SRasesh Mody 	}
3988b230ed8SRasesh Mody 
3998b230ed8SRasesh Mody 	if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs /
4008b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT) {
4018b230ed8SRasesh Mody 		bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
4028b230ed8SRasesh Mody 						BFI_COALESCING_TIMER_UNIT;
4038b230ed8SRasesh Mody 
4048b230ed8SRasesh Mody 		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED))
4058b230ed8SRasesh Mody 			bnad_rx_coalescing_timeo_set(bnad);
4068b230ed8SRasesh Mody 
4078b230ed8SRasesh Mody 	}
4088b230ed8SRasesh Mody 
4098b230ed8SRasesh Mody 	/* Add Tx Inter-pkt DMA count?  */
4108b230ed8SRasesh Mody 
4118b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
4128b230ed8SRasesh Mody 
4138b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
4148b230ed8SRasesh Mody 	return 0;
4158b230ed8SRasesh Mody }
4168b230ed8SRasesh Mody 
4178b230ed8SRasesh Mody static void
4188b230ed8SRasesh Mody bnad_get_ringparam(struct net_device *netdev,
4198b230ed8SRasesh Mody 		   struct ethtool_ringparam *ringparam)
4208b230ed8SRasesh Mody {
4218b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
4228b230ed8SRasesh Mody 
42341eb5ba4SRasesh Mody 	ringparam->rx_max_pending = BNAD_MAX_RXQ_DEPTH;
42441eb5ba4SRasesh Mody 	ringparam->tx_max_pending = BNAD_MAX_TXQ_DEPTH;
4258b230ed8SRasesh Mody 
4268b230ed8SRasesh Mody 	ringparam->rx_pending = bnad->rxq_depth;
4278b230ed8SRasesh Mody 	ringparam->tx_pending = bnad->txq_depth;
4288b230ed8SRasesh Mody }
4298b230ed8SRasesh Mody 
4308b230ed8SRasesh Mody static int
4318b230ed8SRasesh Mody bnad_set_ringparam(struct net_device *netdev,
4328b230ed8SRasesh Mody 		   struct ethtool_ringparam *ringparam)
4338b230ed8SRasesh Mody {
4348b230ed8SRasesh Mody 	int i, current_err, err = 0;
4358b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
436a2122d95SRasesh Mody 	unsigned long flags;
4378b230ed8SRasesh Mody 
4388b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
4398b230ed8SRasesh Mody 	if (ringparam->rx_pending == bnad->rxq_depth &&
4408b230ed8SRasesh Mody 	    ringparam->tx_pending == bnad->txq_depth) {
4418b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4428b230ed8SRasesh Mody 		return 0;
4438b230ed8SRasesh Mody 	}
4448b230ed8SRasesh Mody 
4458b230ed8SRasesh Mody 	if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
44641eb5ba4SRasesh Mody 	    ringparam->rx_pending > BNAD_MAX_RXQ_DEPTH ||
4478b230ed8SRasesh Mody 	    !BNA_POWER_OF_2(ringparam->rx_pending)) {
4488b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4498b230ed8SRasesh Mody 		return -EINVAL;
4508b230ed8SRasesh Mody 	}
4518b230ed8SRasesh Mody 	if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
45241eb5ba4SRasesh Mody 	    ringparam->tx_pending > BNAD_MAX_TXQ_DEPTH ||
4538b230ed8SRasesh Mody 	    !BNA_POWER_OF_2(ringparam->tx_pending)) {
4548b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4558b230ed8SRasesh Mody 		return -EINVAL;
4568b230ed8SRasesh Mody 	}
4578b230ed8SRasesh Mody 
4588b230ed8SRasesh Mody 	if (ringparam->rx_pending != bnad->rxq_depth) {
4598b230ed8SRasesh Mody 		bnad->rxq_depth = ringparam->rx_pending;
460a2122d95SRasesh Mody 		if (!netif_running(netdev)) {
461a2122d95SRasesh Mody 			mutex_unlock(&bnad->conf_mutex);
462a2122d95SRasesh Mody 			return 0;
463a2122d95SRasesh Mody 		}
464a2122d95SRasesh Mody 
4658b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
4668b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
4678b230ed8SRasesh Mody 				continue;
468b3cc6e88SJing Huang 			bnad_destroy_rx(bnad, i);
4698b230ed8SRasesh Mody 			current_err = bnad_setup_rx(bnad, i);
4708b230ed8SRasesh Mody 			if (current_err && !err)
4718b230ed8SRasesh Mody 				err = current_err;
472a2122d95SRasesh Mody 		}
473a2122d95SRasesh Mody 
474a2122d95SRasesh Mody 		if (!err && bnad->rx_info[0].rx) {
475a2122d95SRasesh Mody 			/* restore rx configuration */
4763fb9852fSRasesh Mody 			bnad_restore_vlans(bnad, 0);
477a2122d95SRasesh Mody 			bnad_enable_default_bcast(bnad);
478a2122d95SRasesh Mody 			spin_lock_irqsave(&bnad->bna_lock, flags);
479a2122d95SRasesh Mody 			bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
480a2122d95SRasesh Mody 			spin_unlock_irqrestore(&bnad->bna_lock, flags);
4813fb9852fSRasesh Mody 			bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI |
4823fb9852fSRasesh Mody 					     BNAD_CF_PROMISC);
483a2122d95SRasesh Mody 			bnad_set_rx_mode(netdev);
4848b230ed8SRasesh Mody 		}
4858b230ed8SRasesh Mody 	}
4868b230ed8SRasesh Mody 	if (ringparam->tx_pending != bnad->txq_depth) {
4878b230ed8SRasesh Mody 		bnad->txq_depth = ringparam->tx_pending;
488a2122d95SRasesh Mody 		if (!netif_running(netdev)) {
489a2122d95SRasesh Mody 			mutex_unlock(&bnad->conf_mutex);
490a2122d95SRasesh Mody 			return 0;
491a2122d95SRasesh Mody 		}
492a2122d95SRasesh Mody 
4938b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_tx; i++) {
4948b230ed8SRasesh Mody 			if (!bnad->tx_info[i].tx)
4958b230ed8SRasesh Mody 				continue;
496b3cc6e88SJing Huang 			bnad_destroy_tx(bnad, i);
4978b230ed8SRasesh Mody 			current_err = bnad_setup_tx(bnad, i);
4988b230ed8SRasesh Mody 			if (current_err && !err)
4998b230ed8SRasesh Mody 				err = current_err;
5008b230ed8SRasesh Mody 		}
5018b230ed8SRasesh Mody 	}
5028b230ed8SRasesh Mody 
5038b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
5048b230ed8SRasesh Mody 	return err;
5058b230ed8SRasesh Mody }
5068b230ed8SRasesh Mody 
5078b230ed8SRasesh Mody static void
5088b230ed8SRasesh Mody bnad_get_pauseparam(struct net_device *netdev,
5098b230ed8SRasesh Mody 		    struct ethtool_pauseparam *pauseparam)
5108b230ed8SRasesh Mody {
5118b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5128b230ed8SRasesh Mody 
5138b230ed8SRasesh Mody 	pauseparam->autoneg = 0;
514078086f3SRasesh Mody 	pauseparam->rx_pause = bnad->bna.enet.pause_config.rx_pause;
515078086f3SRasesh Mody 	pauseparam->tx_pause = bnad->bna.enet.pause_config.tx_pause;
5168b230ed8SRasesh Mody }
5178b230ed8SRasesh Mody 
5188b230ed8SRasesh Mody static int
5198b230ed8SRasesh Mody bnad_set_pauseparam(struct net_device *netdev,
5208b230ed8SRasesh Mody 		    struct ethtool_pauseparam *pauseparam)
5218b230ed8SRasesh Mody {
5228b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5238b230ed8SRasesh Mody 	struct bna_pause_config pause_config;
5248b230ed8SRasesh Mody 	unsigned long flags;
5258b230ed8SRasesh Mody 
5268b230ed8SRasesh Mody 	if (pauseparam->autoneg == AUTONEG_ENABLE)
5278b230ed8SRasesh Mody 		return -EINVAL;
5288b230ed8SRasesh Mody 
5298b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
530078086f3SRasesh Mody 	if (pauseparam->rx_pause != bnad->bna.enet.pause_config.rx_pause ||
531078086f3SRasesh Mody 	    pauseparam->tx_pause != bnad->bna.enet.pause_config.tx_pause) {
5328b230ed8SRasesh Mody 		pause_config.rx_pause = pauseparam->rx_pause;
5338b230ed8SRasesh Mody 		pause_config.tx_pause = pauseparam->tx_pause;
5348b230ed8SRasesh Mody 		spin_lock_irqsave(&bnad->bna_lock, flags);
535078086f3SRasesh Mody 		bna_enet_pause_config(&bnad->bna.enet, &pause_config, NULL);
5368b230ed8SRasesh Mody 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
5378b230ed8SRasesh Mody 	}
5388b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
5398b230ed8SRasesh Mody 	return 0;
5408b230ed8SRasesh Mody }
5418b230ed8SRasesh Mody 
5428b230ed8SRasesh Mody static void
5438b230ed8SRasesh Mody bnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string)
5448b230ed8SRasesh Mody {
5458b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5468b230ed8SRasesh Mody 	int i, j, q_num;
547078086f3SRasesh Mody 	u32 bmap;
5488b230ed8SRasesh Mody 
5498b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
5508b230ed8SRasesh Mody 
5518b230ed8SRasesh Mody 	switch (stringset) {
5528b230ed8SRasesh Mody 	case ETH_SS_STATS:
5538b230ed8SRasesh Mody 		for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
5548b230ed8SRasesh Mody 			BUG_ON(!(strlen(bnad_net_stats_strings[i]) <
5558b230ed8SRasesh Mody 				   ETH_GSTRING_LEN));
5568b230ed8SRasesh Mody 			memcpy(string, bnad_net_stats_strings[i],
5578b230ed8SRasesh Mody 			       ETH_GSTRING_LEN);
5588b230ed8SRasesh Mody 			string += ETH_GSTRING_LEN;
5598b230ed8SRasesh Mody 		}
560078086f3SRasesh Mody 		bmap = bna_tx_rid_mask(&bnad->bna);
561078086f3SRasesh Mody 		for (i = 0; bmap; i++) {
5628b230ed8SRasesh Mody 			if (bmap & 1) {
5638b230ed8SRasesh Mody 				sprintf(string, "txf%d_ucast_octets", i);
5648b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5658b230ed8SRasesh Mody 				sprintf(string, "txf%d_ucast", i);
5668b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5678b230ed8SRasesh Mody 				sprintf(string, "txf%d_ucast_vlan", i);
5688b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5698b230ed8SRasesh Mody 				sprintf(string, "txf%d_mcast_octets", i);
5708b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5718b230ed8SRasesh Mody 				sprintf(string, "txf%d_mcast", i);
5728b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5738b230ed8SRasesh Mody 				sprintf(string, "txf%d_mcast_vlan", i);
5748b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5758b230ed8SRasesh Mody 				sprintf(string, "txf%d_bcast_octets", i);
5768b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5778b230ed8SRasesh Mody 				sprintf(string, "txf%d_bcast", i);
5788b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5798b230ed8SRasesh Mody 				sprintf(string, "txf%d_bcast_vlan", i);
5808b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5818b230ed8SRasesh Mody 				sprintf(string, "txf%d_errors", i);
5828b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5838b230ed8SRasesh Mody 				sprintf(string, "txf%d_filter_vlan", i);
5848b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5858b230ed8SRasesh Mody 				sprintf(string, "txf%d_filter_mac_sa", i);
5868b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5878b230ed8SRasesh Mody 			}
5888b230ed8SRasesh Mody 			bmap >>= 1;
5898b230ed8SRasesh Mody 		}
5908b230ed8SRasesh Mody 
591078086f3SRasesh Mody 		bmap = bna_rx_rid_mask(&bnad->bna);
592078086f3SRasesh Mody 		for (i = 0; bmap; i++) {
5938b230ed8SRasesh Mody 			if (bmap & 1) {
5948b230ed8SRasesh Mody 				sprintf(string, "rxf%d_ucast_octets", i);
5958b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5968b230ed8SRasesh Mody 				sprintf(string, "rxf%d_ucast", i);
5978b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
5988b230ed8SRasesh Mody 				sprintf(string, "rxf%d_ucast_vlan", i);
5998b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6008b230ed8SRasesh Mody 				sprintf(string, "rxf%d_mcast_octets", i);
6018b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6028b230ed8SRasesh Mody 				sprintf(string, "rxf%d_mcast", i);
6038b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6048b230ed8SRasesh Mody 				sprintf(string, "rxf%d_mcast_vlan", i);
6058b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6068b230ed8SRasesh Mody 				sprintf(string, "rxf%d_bcast_octets", i);
6078b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6088b230ed8SRasesh Mody 				sprintf(string, "rxf%d_bcast", i);
6098b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6108b230ed8SRasesh Mody 				sprintf(string, "rxf%d_bcast_vlan", i);
6118b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6128b230ed8SRasesh Mody 				sprintf(string, "rxf%d_frame_drops", i);
6138b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6148b230ed8SRasesh Mody 			}
6158b230ed8SRasesh Mody 			bmap >>= 1;
6168b230ed8SRasesh Mody 		}
6178b230ed8SRasesh Mody 
6188b230ed8SRasesh Mody 		q_num = 0;
6198b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
6208b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
6218b230ed8SRasesh Mody 				continue;
6228b230ed8SRasesh Mody 			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
6238b230ed8SRasesh Mody 				sprintf(string, "cq%d_producer_index", q_num);
6248b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6258b230ed8SRasesh Mody 				sprintf(string, "cq%d_consumer_index", q_num);
6268b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6278b230ed8SRasesh Mody 				sprintf(string, "cq%d_hw_producer_index",
6288b230ed8SRasesh Mody 					q_num);
6298b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
630a2122d95SRasesh Mody 				sprintf(string, "cq%d_intr", q_num);
631a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
632a2122d95SRasesh Mody 				sprintf(string, "cq%d_poll", q_num);
633a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
634a2122d95SRasesh Mody 				sprintf(string, "cq%d_schedule", q_num);
635a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
636a2122d95SRasesh Mody 				sprintf(string, "cq%d_keep_poll", q_num);
637a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
638a2122d95SRasesh Mody 				sprintf(string, "cq%d_complete", q_num);
639a2122d95SRasesh Mody 				string += ETH_GSTRING_LEN;
6408b230ed8SRasesh Mody 				q_num++;
6418b230ed8SRasesh Mody 			}
6428b230ed8SRasesh Mody 		}
6438b230ed8SRasesh Mody 
6448b230ed8SRasesh Mody 		q_num = 0;
6458b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
6468b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
6478b230ed8SRasesh Mody 				continue;
6488b230ed8SRasesh Mody 			for (j = 0; j < bnad->num_rxp_per_rx; j++) {
6498b230ed8SRasesh Mody 				sprintf(string, "rxq%d_packets", q_num);
6508b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6518b230ed8SRasesh Mody 				sprintf(string, "rxq%d_bytes", q_num);
6528b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6538b230ed8SRasesh Mody 				sprintf(string, "rxq%d_packets_with_error",
6548b230ed8SRasesh Mody 								q_num);
6558b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6568b230ed8SRasesh Mody 				sprintf(string, "rxq%d_allocbuf_failed", q_num);
6578b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6588b230ed8SRasesh Mody 				sprintf(string, "rxq%d_producer_index", q_num);
6598b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6608b230ed8SRasesh Mody 				sprintf(string, "rxq%d_consumer_index", q_num);
6618b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6628b230ed8SRasesh Mody 				q_num++;
6638b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb &&
6648b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
6658b230ed8SRasesh Mody 					rcb[1] &&
6668b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
6678b230ed8SRasesh Mody 					rcb[1]->rxq) {
6688b230ed8SRasesh Mody 					sprintf(string, "rxq%d_packets", q_num);
6698b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6708b230ed8SRasesh Mody 					sprintf(string, "rxq%d_bytes", q_num);
6718b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6728b230ed8SRasesh Mody 					sprintf(string,
6738b230ed8SRasesh Mody 					"rxq%d_packets_with_error", q_num);
6748b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6758b230ed8SRasesh Mody 					sprintf(string, "rxq%d_allocbuf_failed",
6768b230ed8SRasesh Mody 								q_num);
6778b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6788b230ed8SRasesh Mody 					sprintf(string, "rxq%d_producer_index",
6798b230ed8SRasesh Mody 								q_num);
6808b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6818b230ed8SRasesh Mody 					sprintf(string, "rxq%d_consumer_index",
6828b230ed8SRasesh Mody 								q_num);
6838b230ed8SRasesh Mody 					string += ETH_GSTRING_LEN;
6848b230ed8SRasesh Mody 					q_num++;
6858b230ed8SRasesh Mody 				}
6868b230ed8SRasesh Mody 			}
6878b230ed8SRasesh Mody 		}
6888b230ed8SRasesh Mody 
6898b230ed8SRasesh Mody 		q_num = 0;
6908b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_tx; i++) {
6918b230ed8SRasesh Mody 			if (!bnad->tx_info[i].tx)
6928b230ed8SRasesh Mody 				continue;
6938b230ed8SRasesh Mody 			for (j = 0; j < bnad->num_txq_per_tx; j++) {
6948b230ed8SRasesh Mody 				sprintf(string, "txq%d_packets", q_num);
6958b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6968b230ed8SRasesh Mody 				sprintf(string, "txq%d_bytes", q_num);
6978b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
6988b230ed8SRasesh Mody 				sprintf(string, "txq%d_producer_index", q_num);
6998b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
7008b230ed8SRasesh Mody 				sprintf(string, "txq%d_consumer_index", q_num);
7018b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
7028b230ed8SRasesh Mody 				sprintf(string, "txq%d_hw_consumer_index",
7038b230ed8SRasesh Mody 									q_num);
7048b230ed8SRasesh Mody 				string += ETH_GSTRING_LEN;
7058b230ed8SRasesh Mody 				q_num++;
7068b230ed8SRasesh Mody 			}
7078b230ed8SRasesh Mody 		}
7088b230ed8SRasesh Mody 
7098b230ed8SRasesh Mody 		break;
7108b230ed8SRasesh Mody 
7118b230ed8SRasesh Mody 	default:
7128b230ed8SRasesh Mody 		break;
7138b230ed8SRasesh Mody 	}
7148b230ed8SRasesh Mody 
7158b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
7168b230ed8SRasesh Mody }
7178b230ed8SRasesh Mody 
7188b230ed8SRasesh Mody static int
7198b230ed8SRasesh Mody bnad_get_stats_count_locked(struct net_device *netdev)
7208b230ed8SRasesh Mody {
7218b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
722a2122d95SRasesh Mody 	int i, j, count = 0, rxf_active_num = 0, txf_active_num = 0;
723078086f3SRasesh Mody 	u32 bmap;
7248b230ed8SRasesh Mody 
725078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
726078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
7278b230ed8SRasesh Mody 		if (bmap & 1)
7288b230ed8SRasesh Mody 			txf_active_num++;
7298b230ed8SRasesh Mody 		bmap >>= 1;
7308b230ed8SRasesh Mody 	}
731078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
732078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
7338b230ed8SRasesh Mody 		if (bmap & 1)
7348b230ed8SRasesh Mody 			rxf_active_num++;
7358b230ed8SRasesh Mody 		bmap >>= 1;
7368b230ed8SRasesh Mody 	}
7378b230ed8SRasesh Mody 	count = BNAD_ETHTOOL_STATS_NUM +
7388b230ed8SRasesh Mody 		txf_active_num * BNAD_NUM_TXF_COUNTERS +
7398b230ed8SRasesh Mody 		rxf_active_num * BNAD_NUM_RXF_COUNTERS;
7408b230ed8SRasesh Mody 
7418b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7428b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7438b230ed8SRasesh Mody 			continue;
7448b230ed8SRasesh Mody 		count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS;
7458b230ed8SRasesh Mody 		count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS;
7468b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7478b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
7488b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
7498b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
7508b230ed8SRasesh Mody 				count +=  BNAD_NUM_RXQ_COUNTERS;
7518b230ed8SRasesh Mody 	}
7528b230ed8SRasesh Mody 
7538b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
7548b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
7558b230ed8SRasesh Mody 			continue;
7568b230ed8SRasesh Mody 		count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS;
7578b230ed8SRasesh Mody 	}
7588b230ed8SRasesh Mody 	return count;
7598b230ed8SRasesh Mody }
7608b230ed8SRasesh Mody 
7618b230ed8SRasesh Mody static int
7628b230ed8SRasesh Mody bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
7638b230ed8SRasesh Mody {
7648b230ed8SRasesh Mody 	int i, j;
7658b230ed8SRasesh Mody 	struct bna_rcb *rcb = NULL;
7668b230ed8SRasesh Mody 	struct bna_tcb *tcb = NULL;
7678b230ed8SRasesh Mody 
7688b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7698b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7708b230ed8SRasesh Mody 			continue;
7718b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7728b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
7738b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
7748b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) {
7758b230ed8SRasesh Mody 				buf[bi++] = bnad->rx_info[i].rx_ctrl[j].
7768b230ed8SRasesh Mody 						ccb->producer_index;
7778b230ed8SRasesh Mody 				buf[bi++] = 0; /* ccb->consumer_index */
7788b230ed8SRasesh Mody 				buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
7798b230ed8SRasesh Mody 						ccb->hw_producer_index);
780a2122d95SRasesh Mody 
781a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
782a2122d95SRasesh Mody 						rx_ctrl[j].rx_intr_ctr;
783a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
784a2122d95SRasesh Mody 						rx_ctrl[j].rx_poll_ctr;
785a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
786a2122d95SRasesh Mody 						rx_ctrl[j].rx_schedule;
787a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
788a2122d95SRasesh Mody 						rx_ctrl[j].rx_keep_poll;
789a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
790a2122d95SRasesh Mody 						rx_ctrl[j].rx_complete;
7918b230ed8SRasesh Mody 			}
7928b230ed8SRasesh Mody 	}
7938b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7948b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7958b230ed8SRasesh Mody 			continue;
7968b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7978b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb) {
7988b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
7998b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
8008b230ed8SRasesh Mody 					rcb[0]->rxq) {
8018b230ed8SRasesh Mody 					rcb = bnad->rx_info[i].rx_ctrl[j].
8028b230ed8SRasesh Mody 							ccb->rcb[0];
8038b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_packets;
8048b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_bytes;
8058b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8068b230ed8SRasesh Mody 							rx_packets_with_error;
8078b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8088b230ed8SRasesh Mody 							rxbuf_alloc_failed;
8098b230ed8SRasesh Mody 					buf[bi++] = rcb->producer_index;
8108b230ed8SRasesh Mody 					buf[bi++] = rcb->consumer_index;
8118b230ed8SRasesh Mody 				}
8128b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
8138b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
8148b230ed8SRasesh Mody 					rcb[1]->rxq) {
8158b230ed8SRasesh Mody 					rcb = bnad->rx_info[i].rx_ctrl[j].
8168b230ed8SRasesh Mody 								ccb->rcb[1];
8178b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_packets;
8188b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_bytes;
8198b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8208b230ed8SRasesh Mody 							rx_packets_with_error;
8218b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
8228b230ed8SRasesh Mody 							rxbuf_alloc_failed;
8238b230ed8SRasesh Mody 					buf[bi++] = rcb->producer_index;
8248b230ed8SRasesh Mody 					buf[bi++] = rcb->consumer_index;
8258b230ed8SRasesh Mody 				}
8268b230ed8SRasesh Mody 			}
8278b230ed8SRasesh Mody 	}
8288b230ed8SRasesh Mody 
8298b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
8308b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
8318b230ed8SRasesh Mody 			continue;
8328b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_txq_per_tx; j++)
8338b230ed8SRasesh Mody 			if (bnad->tx_info[i].tcb[j] &&
8348b230ed8SRasesh Mody 				bnad->tx_info[i].tcb[j]->txq) {
8358b230ed8SRasesh Mody 				tcb = bnad->tx_info[i].tcb[j];
8368b230ed8SRasesh Mody 				buf[bi++] = tcb->txq->tx_packets;
8378b230ed8SRasesh Mody 				buf[bi++] = tcb->txq->tx_bytes;
8388b230ed8SRasesh Mody 				buf[bi++] = tcb->producer_index;
8398b230ed8SRasesh Mody 				buf[bi++] = tcb->consumer_index;
8408b230ed8SRasesh Mody 				buf[bi++] = *(tcb->hw_consumer_index);
8418b230ed8SRasesh Mody 			}
8428b230ed8SRasesh Mody 	}
8438b230ed8SRasesh Mody 
8448b230ed8SRasesh Mody 	return bi;
8458b230ed8SRasesh Mody }
8468b230ed8SRasesh Mody 
8478b230ed8SRasesh Mody static void
8488b230ed8SRasesh Mody bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
8498b230ed8SRasesh Mody 		       u64 *buf)
8508b230ed8SRasesh Mody {
8518b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
8528b230ed8SRasesh Mody 	int i, j, bi;
853250e061eSEric Dumazet 	unsigned long flags;
854250e061eSEric Dumazet 	struct rtnl_link_stats64 *net_stats64;
8558b230ed8SRasesh Mody 	u64 *stats64;
856078086f3SRasesh Mody 	u32 bmap;
8578b230ed8SRasesh Mody 
8588b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
8598b230ed8SRasesh Mody 	if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
8608b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
8618b230ed8SRasesh Mody 		return;
8628b230ed8SRasesh Mody 	}
8638b230ed8SRasesh Mody 
8648b230ed8SRasesh Mody 	/*
8658b230ed8SRasesh Mody 	 * Used bna_lock to sync reads from bna_stats, which is written
8668b230ed8SRasesh Mody 	 * under the same lock
8678b230ed8SRasesh Mody 	 */
8688b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
8698b230ed8SRasesh Mody 	bi = 0;
8708b230ed8SRasesh Mody 	memset(buf, 0, stats->n_stats * sizeof(u64));
8718b230ed8SRasesh Mody 
872250e061eSEric Dumazet 	net_stats64 = (struct rtnl_link_stats64 *)buf;
873250e061eSEric Dumazet 	bnad_netdev_qstats_fill(bnad, net_stats64);
874250e061eSEric Dumazet 	bnad_netdev_hwstats_fill(bnad, net_stats64);
8758b230ed8SRasesh Mody 
876250e061eSEric Dumazet 	bi = sizeof(*net_stats64) / sizeof(u64);
8778b230ed8SRasesh Mody 
878f7c0fa4cSRasesh Mody 	/* Get netif_queue_stopped from stack */
879f7c0fa4cSRasesh Mody 	bnad->stats.drv_stats.netif_queue_stopped = netif_queue_stopped(netdev);
880f7c0fa4cSRasesh Mody 
8818b230ed8SRasesh Mody 	/* Fill driver stats into ethtool buffers */
8828b230ed8SRasesh Mody 	stats64 = (u64 *)&bnad->stats.drv_stats;
8838b230ed8SRasesh Mody 	for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
8848b230ed8SRasesh Mody 		buf[bi++] = stats64[i];
8858b230ed8SRasesh Mody 
8868b230ed8SRasesh Mody 	/* Fill hardware stats excluding the rxf/txf into ethtool bufs */
887078086f3SRasesh Mody 	stats64 = (u64 *) &bnad->stats.bna_stats->hw_stats;
8888b230ed8SRasesh Mody 	for (i = 0;
889078086f3SRasesh Mody 	     i < offsetof(struct bfi_enet_stats, rxf_stats[0]) /
890078086f3SRasesh Mody 		sizeof(u64);
8918b230ed8SRasesh Mody 	     i++)
8928b230ed8SRasesh Mody 		buf[bi++] = stats64[i];
8938b230ed8SRasesh Mody 
8948b230ed8SRasesh Mody 	/* Fill txf stats into ethtool buffers */
895078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
896078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
8978b230ed8SRasesh Mody 		if (bmap & 1) {
8988b230ed8SRasesh Mody 			stats64 = (u64 *)&bnad->stats.bna_stats->
899078086f3SRasesh Mody 						hw_stats.txf_stats[i];
900078086f3SRasesh Mody 			for (j = 0; j < sizeof(struct bfi_enet_stats_txf) /
9018b230ed8SRasesh Mody 					sizeof(u64); j++)
9028b230ed8SRasesh Mody 				buf[bi++] = stats64[j];
9038b230ed8SRasesh Mody 		}
9048b230ed8SRasesh Mody 		bmap >>= 1;
9058b230ed8SRasesh Mody 	}
9068b230ed8SRasesh Mody 
9078b230ed8SRasesh Mody 	/*  Fill rxf stats into ethtool buffers */
908078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
909078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
9108b230ed8SRasesh Mody 		if (bmap & 1) {
9118b230ed8SRasesh Mody 			stats64 = (u64 *)&bnad->stats.bna_stats->
912078086f3SRasesh Mody 						hw_stats.rxf_stats[i];
913078086f3SRasesh Mody 			for (j = 0; j < sizeof(struct bfi_enet_stats_rxf) /
9148b230ed8SRasesh Mody 					sizeof(u64); j++)
9158b230ed8SRasesh Mody 				buf[bi++] = stats64[j];
9168b230ed8SRasesh Mody 		}
9178b230ed8SRasesh Mody 		bmap >>= 1;
9188b230ed8SRasesh Mody 	}
9198b230ed8SRasesh Mody 
9208b230ed8SRasesh Mody 	/* Fill per Q stats into ethtool buffers */
9218b230ed8SRasesh Mody 	bi = bnad_per_q_stats_fill(bnad, buf, bi);
9228b230ed8SRasesh Mody 
9238b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
9248b230ed8SRasesh Mody 
9258b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
9268b230ed8SRasesh Mody }
9278b230ed8SRasesh Mody 
9288b230ed8SRasesh Mody static int
9298b230ed8SRasesh Mody bnad_get_sset_count(struct net_device *netdev, int sset)
9308b230ed8SRasesh Mody {
9318b230ed8SRasesh Mody 	switch (sset) {
9328b230ed8SRasesh Mody 	case ETH_SS_STATS:
9338b230ed8SRasesh Mody 		return bnad_get_stats_count_locked(netdev);
9348b230ed8SRasesh Mody 	default:
9358b230ed8SRasesh Mody 		return -EOPNOTSUPP;
9368b230ed8SRasesh Mody 	}
9378b230ed8SRasesh Mody }
9388b230ed8SRasesh Mody 
93972a9730bSKrishna Gudipati static u32
94072a9730bSKrishna Gudipati bnad_get_flash_partition_by_offset(struct bnad *bnad, u32 offset,
94172a9730bSKrishna Gudipati 				u32 *base_offset)
94272a9730bSKrishna Gudipati {
94372a9730bSKrishna Gudipati 	struct bfa_flash_attr *flash_attr;
94472a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
94572a9730bSKrishna Gudipati 	u32 i, flash_part = 0, ret;
94672a9730bSKrishna Gudipati 	unsigned long flags = 0;
94772a9730bSKrishna Gudipati 
94872a9730bSKrishna Gudipati 	flash_attr = kzalloc(sizeof(struct bfa_flash_attr), GFP_KERNEL);
94972a9730bSKrishna Gudipati 	if (!flash_attr)
950027a3b61SDan Carpenter 		return 0;
95172a9730bSKrishna Gudipati 
95272a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
95372a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
95472a9730bSKrishna Gudipati 
95572a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
95672a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
95772a9730bSKrishna Gudipati 	ret = bfa_nw_flash_get_attr(&bnad->bna.flash, flash_attr,
95872a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
95972a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
96072a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
96172a9730bSKrishna Gudipati 		kfree(flash_attr);
962027a3b61SDan Carpenter 		return 0;
96372a9730bSKrishna Gudipati 	}
96472a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
96572a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
96672a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
96772a9730bSKrishna Gudipati 
96872a9730bSKrishna Gudipati 	/* Check for the flash type & base offset value */
96972a9730bSKrishna Gudipati 	if (ret == BFA_STATUS_OK) {
97072a9730bSKrishna Gudipati 		for (i = 0; i < flash_attr->npart; i++) {
97172a9730bSKrishna Gudipati 			if (offset >= flash_attr->part[i].part_off &&
97272a9730bSKrishna Gudipati 			    offset < (flash_attr->part[i].part_off +
97372a9730bSKrishna Gudipati 				      flash_attr->part[i].part_size)) {
97472a9730bSKrishna Gudipati 				flash_part = flash_attr->part[i].part_type;
97572a9730bSKrishna Gudipati 				*base_offset = flash_attr->part[i].part_off;
97672a9730bSKrishna Gudipati 				break;
97772a9730bSKrishna Gudipati 			}
97872a9730bSKrishna Gudipati 		}
97972a9730bSKrishna Gudipati 	}
98072a9730bSKrishna Gudipati 	kfree(flash_attr);
98172a9730bSKrishna Gudipati 	return flash_part;
98272a9730bSKrishna Gudipati }
98372a9730bSKrishna Gudipati 
98472a9730bSKrishna Gudipati static int
98572a9730bSKrishna Gudipati bnad_get_eeprom_len(struct net_device *netdev)
98672a9730bSKrishna Gudipati {
98772a9730bSKrishna Gudipati 	return BFA_TOTAL_FLASH_SIZE;
98872a9730bSKrishna Gudipati }
98972a9730bSKrishna Gudipati 
99072a9730bSKrishna Gudipati static int
99172a9730bSKrishna Gudipati bnad_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
99272a9730bSKrishna Gudipati 		u8 *bytes)
99372a9730bSKrishna Gudipati {
99472a9730bSKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
99572a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
99672a9730bSKrishna Gudipati 	u32 flash_part = 0, base_offset = 0;
99772a9730bSKrishna Gudipati 	unsigned long flags = 0;
99872a9730bSKrishna Gudipati 	int ret = 0;
99972a9730bSKrishna Gudipati 
100072a9730bSKrishna Gudipati 	/* Check if the flash read request is valid */
100172a9730bSKrishna Gudipati 	if (eeprom->magic != (bnad->pcidev->vendor |
100272a9730bSKrishna Gudipati 			     (bnad->pcidev->device << 16)))
100372a9730bSKrishna Gudipati 		return -EFAULT;
100472a9730bSKrishna Gudipati 
100572a9730bSKrishna Gudipati 	/* Query the flash partition based on the offset */
100672a9730bSKrishna Gudipati 	flash_part = bnad_get_flash_partition_by_offset(bnad,
100772a9730bSKrishna Gudipati 				eeprom->offset, &base_offset);
1008027a3b61SDan Carpenter 	if (flash_part == 0)
100972a9730bSKrishna Gudipati 		return -EFAULT;
101072a9730bSKrishna Gudipati 
101172a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
101272a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
101372a9730bSKrishna Gudipati 
101472a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
101572a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
101672a9730bSKrishna Gudipati 	ret = bfa_nw_flash_read_part(&bnad->bna.flash, flash_part,
101772a9730bSKrishna Gudipati 				bnad->id, bytes, eeprom->len,
101872a9730bSKrishna Gudipati 				eeprom->offset - base_offset,
101972a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
102072a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
102172a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
102272a9730bSKrishna Gudipati 		goto done;
102372a9730bSKrishna Gudipati 	}
102472a9730bSKrishna Gudipati 
102572a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
102672a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
102772a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
102872a9730bSKrishna Gudipati done:
102972a9730bSKrishna Gudipati 	return ret;
103072a9730bSKrishna Gudipati }
103172a9730bSKrishna Gudipati 
103272a9730bSKrishna Gudipati static int
103372a9730bSKrishna Gudipati bnad_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
103472a9730bSKrishna Gudipati 		u8 *bytes)
103572a9730bSKrishna Gudipati {
103672a9730bSKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
103772a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
103872a9730bSKrishna Gudipati 	u32 flash_part = 0, base_offset = 0;
103972a9730bSKrishna Gudipati 	unsigned long flags = 0;
104072a9730bSKrishna Gudipati 	int ret = 0;
104172a9730bSKrishna Gudipati 
104272a9730bSKrishna Gudipati 	/* Check if the flash update request is valid */
104372a9730bSKrishna Gudipati 	if (eeprom->magic != (bnad->pcidev->vendor |
104472a9730bSKrishna Gudipati 			     (bnad->pcidev->device << 16)))
104572a9730bSKrishna Gudipati 		return -EINVAL;
104672a9730bSKrishna Gudipati 
104772a9730bSKrishna Gudipati 	/* Query the flash partition based on the offset */
104872a9730bSKrishna Gudipati 	flash_part = bnad_get_flash_partition_by_offset(bnad,
104972a9730bSKrishna Gudipati 				eeprom->offset, &base_offset);
1050027a3b61SDan Carpenter 	if (flash_part == 0)
105172a9730bSKrishna Gudipati 		return -EFAULT;
105272a9730bSKrishna Gudipati 
105372a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
105472a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
105572a9730bSKrishna Gudipati 
105672a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
105772a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
105872a9730bSKrishna Gudipati 	ret = bfa_nw_flash_update_part(&bnad->bna.flash, flash_part,
105972a9730bSKrishna Gudipati 				bnad->id, bytes, eeprom->len,
106072a9730bSKrishna Gudipati 				eeprom->offset - base_offset,
106172a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
106272a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
106372a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
106472a9730bSKrishna Gudipati 		goto done;
106572a9730bSKrishna Gudipati 	}
106672a9730bSKrishna Gudipati 
106772a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
106872a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
106972a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
107072a9730bSKrishna Gudipati done:
107172a9730bSKrishna Gudipati 	return ret;
107272a9730bSKrishna Gudipati }
107372a9730bSKrishna Gudipati 
107457b9bef0SKrishna Gudipati static int
107557b9bef0SKrishna Gudipati bnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash)
107657b9bef0SKrishna Gudipati {
107757b9bef0SKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
107857b9bef0SKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
107957b9bef0SKrishna Gudipati 	const struct firmware *fw;
108057b9bef0SKrishna Gudipati 	int ret = 0;
108157b9bef0SKrishna Gudipati 
108257b9bef0SKrishna Gudipati 	ret = request_firmware(&fw, eflash->data, &bnad->pcidev->dev);
108357b9bef0SKrishna Gudipati 	if (ret) {
108457b9bef0SKrishna Gudipati 		pr_err("BNA: Can't locate firmware %s\n", eflash->data);
108557b9bef0SKrishna Gudipati 		goto out;
108657b9bef0SKrishna Gudipati 	}
108757b9bef0SKrishna Gudipati 
108857b9bef0SKrishna Gudipati 	fcomp.bnad = bnad;
108957b9bef0SKrishna Gudipati 	fcomp.comp_status = 0;
109057b9bef0SKrishna Gudipati 
109157b9bef0SKrishna Gudipati 	init_completion(&fcomp.comp);
109257b9bef0SKrishna Gudipati 	spin_lock_irq(&bnad->bna_lock);
109357b9bef0SKrishna Gudipati 	ret = bfa_nw_flash_update_part(&bnad->bna.flash, BFA_FLASH_PART_FWIMG,
109457b9bef0SKrishna Gudipati 				bnad->id, (u8 *)fw->data, fw->size, 0,
109557b9bef0SKrishna Gudipati 				bnad_cb_completion, &fcomp);
109657b9bef0SKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
109757b9bef0SKrishna Gudipati 		pr_warn("BNA: Flash update failed with err: %d\n", ret);
109857b9bef0SKrishna Gudipati 		ret = -EIO;
109957b9bef0SKrishna Gudipati 		spin_unlock_irq(&bnad->bna_lock);
110057b9bef0SKrishna Gudipati 		goto out;
110157b9bef0SKrishna Gudipati 	}
110257b9bef0SKrishna Gudipati 
110357b9bef0SKrishna Gudipati 	spin_unlock_irq(&bnad->bna_lock);
110457b9bef0SKrishna Gudipati 	wait_for_completion(&fcomp.comp);
110557b9bef0SKrishna Gudipati 	if (fcomp.comp_status != BFA_STATUS_OK) {
110657b9bef0SKrishna Gudipati 		ret = -EIO;
110757b9bef0SKrishna Gudipati 		pr_warn("BNA: Firmware image update to flash failed with: %d\n",
110857b9bef0SKrishna Gudipati 			fcomp.comp_status);
110957b9bef0SKrishna Gudipati 	}
111057b9bef0SKrishna Gudipati out:
111157b9bef0SKrishna Gudipati 	release_firmware(fw);
111257b9bef0SKrishna Gudipati 	return ret;
111357b9bef0SKrishna Gudipati }
111457b9bef0SKrishna Gudipati 
1115975419cfSstephen hemminger static const struct ethtool_ops bnad_ethtool_ops = {
11168b230ed8SRasesh Mody 	.get_settings = bnad_get_settings,
11178b230ed8SRasesh Mody 	.set_settings = bnad_set_settings,
11188b230ed8SRasesh Mody 	.get_drvinfo = bnad_get_drvinfo,
11198b230ed8SRasesh Mody 	.get_wol = bnad_get_wol,
11208b230ed8SRasesh Mody 	.get_link = ethtool_op_get_link,
11218b230ed8SRasesh Mody 	.get_coalesce = bnad_get_coalesce,
11228b230ed8SRasesh Mody 	.set_coalesce = bnad_set_coalesce,
11238b230ed8SRasesh Mody 	.get_ringparam = bnad_get_ringparam,
11248b230ed8SRasesh Mody 	.set_ringparam = bnad_set_ringparam,
11258b230ed8SRasesh Mody 	.get_pauseparam = bnad_get_pauseparam,
11268b230ed8SRasesh Mody 	.set_pauseparam = bnad_set_pauseparam,
11278b230ed8SRasesh Mody 	.get_strings = bnad_get_strings,
11288b230ed8SRasesh Mody 	.get_ethtool_stats = bnad_get_ethtool_stats,
112972a9730bSKrishna Gudipati 	.get_sset_count = bnad_get_sset_count,
113072a9730bSKrishna Gudipati 	.get_eeprom_len = bnad_get_eeprom_len,
113172a9730bSKrishna Gudipati 	.get_eeprom = bnad_get_eeprom,
113272a9730bSKrishna Gudipati 	.set_eeprom = bnad_set_eeprom,
113357b9bef0SKrishna Gudipati 	.flash_device = bnad_flash_device,
1134*fee1253eSRasesh Mody 	.get_ts_info = ethtool_op_get_ts_info,
11358b230ed8SRasesh Mody };
11368b230ed8SRasesh Mody 
11378b230ed8SRasesh Mody void
11388b230ed8SRasesh Mody bnad_set_ethtool_ops(struct net_device *netdev)
11398b230ed8SRasesh Mody {
11408b230ed8SRasesh Mody 	SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
11418b230ed8SRasesh Mody }
1142