xref: /linux/drivers/net/ethernet/brocade/bna/bnad_ethtool.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
152fa7bf9SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28b230ed8SRasesh Mody /*
32732ba56SRasesh Mody  * Linux network driver for QLogic BR-series Converged Network Adapter.
48b230ed8SRasesh Mody  */
58b230ed8SRasesh Mody /*
62732ba56SRasesh Mody  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
72732ba56SRasesh Mody  * Copyright (c) 2014-2015 QLogic Corporation
88b230ed8SRasesh Mody  * All rights reserved
92732ba56SRasesh Mody  * www.qlogic.com
108b230ed8SRasesh Mody  */
118b230ed8SRasesh Mody 
128b230ed8SRasesh Mody #include "cna.h"
138b230ed8SRasesh Mody 
148b230ed8SRasesh Mody #include <linux/netdevice.h>
158b230ed8SRasesh Mody #include <linux/skbuff.h>
168b230ed8SRasesh Mody #include <linux/ethtool.h>
178b230ed8SRasesh Mody #include <linux/rtnetlink.h>
188b230ed8SRasesh Mody 
198b230ed8SRasesh Mody #include "bna.h"
208b230ed8SRasesh Mody 
218b230ed8SRasesh Mody #include "bnad.h"
228b230ed8SRasesh Mody 
238b230ed8SRasesh Mody #define BNAD_NUM_TXF_COUNTERS 12
248b230ed8SRasesh Mody #define BNAD_NUM_RXF_COUNTERS 10
25078086f3SRasesh Mody #define BNAD_NUM_CQ_COUNTERS (3 + 5)
262835d2d9SIvan Vecera #define BNAD_NUM_RXQ_COUNTERS 7
278b230ed8SRasesh Mody #define BNAD_NUM_TXQ_COUNTERS 5
288b230ed8SRasesh Mody 
2937dd3482SIvan Vecera static const char *bnad_net_stats_strings[] = {
308b230ed8SRasesh Mody 	"rx_packets",
318b230ed8SRasesh Mody 	"tx_packets",
328b230ed8SRasesh Mody 	"rx_bytes",
338b230ed8SRasesh Mody 	"tx_bytes",
348b230ed8SRasesh Mody 	"rx_errors",
358b230ed8SRasesh Mody 	"tx_errors",
368b230ed8SRasesh Mody 	"rx_dropped",
378b230ed8SRasesh Mody 	"tx_dropped",
388b230ed8SRasesh Mody 	"multicast",
398b230ed8SRasesh Mody 	"collisions",
408b230ed8SRasesh Mody 	"rx_length_errors",
418b230ed8SRasesh Mody 	"rx_crc_errors",
428b230ed8SRasesh Mody 	"rx_frame_errors",
438b230ed8SRasesh Mody 	"tx_fifo_errors",
448b230ed8SRasesh Mody 
458b230ed8SRasesh Mody 	"netif_queue_stop",
468b230ed8SRasesh Mody 	"netif_queue_wakeup",
47f7c0fa4cSRasesh Mody 	"netif_queue_stopped",
488b230ed8SRasesh Mody 	"tso4",
498b230ed8SRasesh Mody 	"tso6",
508b230ed8SRasesh Mody 	"tso_err",
518b230ed8SRasesh Mody 	"tcpcsum_offload",
528b230ed8SRasesh Mody 	"udpcsum_offload",
538b230ed8SRasesh Mody 	"csum_help",
54a2122d95SRasesh Mody 	"tx_skb_too_short",
55a2122d95SRasesh Mody 	"tx_skb_stopping",
56a2122d95SRasesh Mody 	"tx_skb_max_vectors",
57a2122d95SRasesh Mody 	"tx_skb_mss_too_long",
58a2122d95SRasesh Mody 	"tx_skb_tso_too_short",
59a2122d95SRasesh Mody 	"tx_skb_tso_prepare",
60a2122d95SRasesh Mody 	"tx_skb_non_tso_too_long",
61a2122d95SRasesh Mody 	"tx_skb_tcp_hdr",
62a2122d95SRasesh Mody 	"tx_skb_udp_hdr",
63a2122d95SRasesh Mody 	"tx_skb_csum_err",
64a2122d95SRasesh Mody 	"tx_skb_headlen_too_long",
65a2122d95SRasesh Mody 	"tx_skb_headlen_zero",
66a2122d95SRasesh Mody 	"tx_skb_frag_zero",
67a2122d95SRasesh Mody 	"tx_skb_len_mismatch",
68ba5ca784SIvan Vecera 	"tx_skb_map_failed",
698b230ed8SRasesh Mody 	"hw_stats_updates",
708b230ed8SRasesh Mody 	"netif_rx_dropped",
718b230ed8SRasesh Mody 
728b230ed8SRasesh Mody 	"link_toggle",
73a2122d95SRasesh Mody 	"cee_toggle",
748b230ed8SRasesh Mody 
758b230ed8SRasesh Mody 	"rxp_info_alloc_failed",
768b230ed8SRasesh Mody 	"mbox_intr_disabled",
778b230ed8SRasesh Mody 	"mbox_intr_enabled",
788b230ed8SRasesh Mody 	"tx_unmap_q_alloc_failed",
798b230ed8SRasesh Mody 	"rx_unmap_q_alloc_failed",
808b230ed8SRasesh Mody 	"rxbuf_alloc_failed",
81ba5ca784SIvan Vecera 	"rxbuf_map_failed",
828b230ed8SRasesh Mody 
83478ab8c9SRasesh Mody 	"mac_stats_clr_cnt",
848b230ed8SRasesh Mody 	"mac_frame_64",
858b230ed8SRasesh Mody 	"mac_frame_65_127",
868b230ed8SRasesh Mody 	"mac_frame_128_255",
878b230ed8SRasesh Mody 	"mac_frame_256_511",
888b230ed8SRasesh Mody 	"mac_frame_512_1023",
898b230ed8SRasesh Mody 	"mac_frame_1024_1518",
908b230ed8SRasesh Mody 	"mac_frame_1518_1522",
918b230ed8SRasesh Mody 	"mac_rx_bytes",
928b230ed8SRasesh Mody 	"mac_rx_packets",
938b230ed8SRasesh Mody 	"mac_rx_fcs_error",
948b230ed8SRasesh Mody 	"mac_rx_multicast",
958b230ed8SRasesh Mody 	"mac_rx_broadcast",
968b230ed8SRasesh Mody 	"mac_rx_control_frames",
978b230ed8SRasesh Mody 	"mac_rx_pause",
988b230ed8SRasesh Mody 	"mac_rx_unknown_opcode",
998b230ed8SRasesh Mody 	"mac_rx_alignment_error",
1008b230ed8SRasesh Mody 	"mac_rx_frame_length_error",
1018b230ed8SRasesh Mody 	"mac_rx_code_error",
1028b230ed8SRasesh Mody 	"mac_rx_carrier_sense_error",
1038b230ed8SRasesh Mody 	"mac_rx_undersize",
1048b230ed8SRasesh Mody 	"mac_rx_oversize",
1058b230ed8SRasesh Mody 	"mac_rx_fragments",
1068b230ed8SRasesh Mody 	"mac_rx_jabber",
1078b230ed8SRasesh Mody 	"mac_rx_drop",
1088b230ed8SRasesh Mody 
1098b230ed8SRasesh Mody 	"mac_tx_bytes",
1108b230ed8SRasesh Mody 	"mac_tx_packets",
1118b230ed8SRasesh Mody 	"mac_tx_multicast",
1128b230ed8SRasesh Mody 	"mac_tx_broadcast",
1138b230ed8SRasesh Mody 	"mac_tx_pause",
1148b230ed8SRasesh Mody 	"mac_tx_deferral",
1158b230ed8SRasesh Mody 	"mac_tx_excessive_deferral",
1168b230ed8SRasesh Mody 	"mac_tx_single_collision",
1173b882a7bSColin Ian King 	"mac_tx_multiple_collision",
1188b230ed8SRasesh Mody 	"mac_tx_late_collision",
1198b230ed8SRasesh Mody 	"mac_tx_excessive_collision",
1208b230ed8SRasesh Mody 	"mac_tx_total_collision",
1218b230ed8SRasesh Mody 	"mac_tx_pause_honored",
1228b230ed8SRasesh Mody 	"mac_tx_drop",
1238b230ed8SRasesh Mody 	"mac_tx_jabber",
1248b230ed8SRasesh Mody 	"mac_tx_fcs_error",
1258b230ed8SRasesh Mody 	"mac_tx_control_frame",
1268b230ed8SRasesh Mody 	"mac_tx_oversize",
1278b230ed8SRasesh Mody 	"mac_tx_undersize",
1288b230ed8SRasesh Mody 	"mac_tx_fragments",
1298b230ed8SRasesh Mody 
1308b230ed8SRasesh Mody 	"bpc_tx_pause_0",
1318b230ed8SRasesh Mody 	"bpc_tx_pause_1",
1328b230ed8SRasesh Mody 	"bpc_tx_pause_2",
1338b230ed8SRasesh Mody 	"bpc_tx_pause_3",
1348b230ed8SRasesh Mody 	"bpc_tx_pause_4",
1358b230ed8SRasesh Mody 	"bpc_tx_pause_5",
1368b230ed8SRasesh Mody 	"bpc_tx_pause_6",
1378b230ed8SRasesh Mody 	"bpc_tx_pause_7",
1388b230ed8SRasesh Mody 	"bpc_tx_zero_pause_0",
1398b230ed8SRasesh Mody 	"bpc_tx_zero_pause_1",
1408b230ed8SRasesh Mody 	"bpc_tx_zero_pause_2",
1418b230ed8SRasesh Mody 	"bpc_tx_zero_pause_3",
1428b230ed8SRasesh Mody 	"bpc_tx_zero_pause_4",
1438b230ed8SRasesh Mody 	"bpc_tx_zero_pause_5",
1448b230ed8SRasesh Mody 	"bpc_tx_zero_pause_6",
1458b230ed8SRasesh Mody 	"bpc_tx_zero_pause_7",
1468b230ed8SRasesh Mody 	"bpc_tx_first_pause_0",
1478b230ed8SRasesh Mody 	"bpc_tx_first_pause_1",
1488b230ed8SRasesh Mody 	"bpc_tx_first_pause_2",
1498b230ed8SRasesh Mody 	"bpc_tx_first_pause_3",
1508b230ed8SRasesh Mody 	"bpc_tx_first_pause_4",
1518b230ed8SRasesh Mody 	"bpc_tx_first_pause_5",
1528b230ed8SRasesh Mody 	"bpc_tx_first_pause_6",
1538b230ed8SRasesh Mody 	"bpc_tx_first_pause_7",
1548b230ed8SRasesh Mody 
1558b230ed8SRasesh Mody 	"bpc_rx_pause_0",
1568b230ed8SRasesh Mody 	"bpc_rx_pause_1",
1578b230ed8SRasesh Mody 	"bpc_rx_pause_2",
1588b230ed8SRasesh Mody 	"bpc_rx_pause_3",
1598b230ed8SRasesh Mody 	"bpc_rx_pause_4",
1608b230ed8SRasesh Mody 	"bpc_rx_pause_5",
1618b230ed8SRasesh Mody 	"bpc_rx_pause_6",
1628b230ed8SRasesh Mody 	"bpc_rx_pause_7",
1638b230ed8SRasesh Mody 	"bpc_rx_zero_pause_0",
1648b230ed8SRasesh Mody 	"bpc_rx_zero_pause_1",
1658b230ed8SRasesh Mody 	"bpc_rx_zero_pause_2",
1668b230ed8SRasesh Mody 	"bpc_rx_zero_pause_3",
1678b230ed8SRasesh Mody 	"bpc_rx_zero_pause_4",
1688b230ed8SRasesh Mody 	"bpc_rx_zero_pause_5",
1698b230ed8SRasesh Mody 	"bpc_rx_zero_pause_6",
1708b230ed8SRasesh Mody 	"bpc_rx_zero_pause_7",
1718b230ed8SRasesh Mody 	"bpc_rx_first_pause_0",
1728b230ed8SRasesh Mody 	"bpc_rx_first_pause_1",
1738b230ed8SRasesh Mody 	"bpc_rx_first_pause_2",
1748b230ed8SRasesh Mody 	"bpc_rx_first_pause_3",
1758b230ed8SRasesh Mody 	"bpc_rx_first_pause_4",
1768b230ed8SRasesh Mody 	"bpc_rx_first_pause_5",
1778b230ed8SRasesh Mody 	"bpc_rx_first_pause_6",
1788b230ed8SRasesh Mody 	"bpc_rx_first_pause_7",
1798b230ed8SRasesh Mody 
1808b230ed8SRasesh Mody 	"rad_rx_frames",
1818b230ed8SRasesh Mody 	"rad_rx_octets",
1828b230ed8SRasesh Mody 	"rad_rx_vlan_frames",
1838b230ed8SRasesh Mody 	"rad_rx_ucast",
1848b230ed8SRasesh Mody 	"rad_rx_ucast_octets",
1858b230ed8SRasesh Mody 	"rad_rx_ucast_vlan",
1868b230ed8SRasesh Mody 	"rad_rx_mcast",
1878b230ed8SRasesh Mody 	"rad_rx_mcast_octets",
1888b230ed8SRasesh Mody 	"rad_rx_mcast_vlan",
1898b230ed8SRasesh Mody 	"rad_rx_bcast",
1908b230ed8SRasesh Mody 	"rad_rx_bcast_octets",
1918b230ed8SRasesh Mody 	"rad_rx_bcast_vlan",
1928b230ed8SRasesh Mody 	"rad_rx_drops",
1938b230ed8SRasesh Mody 
194a2122d95SRasesh Mody 	"rlb_rad_rx_frames",
195a2122d95SRasesh Mody 	"rlb_rad_rx_octets",
196a2122d95SRasesh Mody 	"rlb_rad_rx_vlan_frames",
197a2122d95SRasesh Mody 	"rlb_rad_rx_ucast",
198a2122d95SRasesh Mody 	"rlb_rad_rx_ucast_octets",
199a2122d95SRasesh Mody 	"rlb_rad_rx_ucast_vlan",
200a2122d95SRasesh Mody 	"rlb_rad_rx_mcast",
201a2122d95SRasesh Mody 	"rlb_rad_rx_mcast_octets",
202a2122d95SRasesh Mody 	"rlb_rad_rx_mcast_vlan",
203a2122d95SRasesh Mody 	"rlb_rad_rx_bcast",
204a2122d95SRasesh Mody 	"rlb_rad_rx_bcast_octets",
205a2122d95SRasesh Mody 	"rlb_rad_rx_bcast_vlan",
206a2122d95SRasesh Mody 	"rlb_rad_rx_drops",
207a2122d95SRasesh Mody 
2088b230ed8SRasesh Mody 	"fc_rx_ucast_octets",
2098b230ed8SRasesh Mody 	"fc_rx_ucast",
2108b230ed8SRasesh Mody 	"fc_rx_ucast_vlan",
2118b230ed8SRasesh Mody 	"fc_rx_mcast_octets",
2128b230ed8SRasesh Mody 	"fc_rx_mcast",
2138b230ed8SRasesh Mody 	"fc_rx_mcast_vlan",
2148b230ed8SRasesh Mody 	"fc_rx_bcast_octets",
2158b230ed8SRasesh Mody 	"fc_rx_bcast",
2168b230ed8SRasesh Mody 	"fc_rx_bcast_vlan",
2178b230ed8SRasesh Mody 
2188b230ed8SRasesh Mody 	"fc_tx_ucast_octets",
2198b230ed8SRasesh Mody 	"fc_tx_ucast",
2208b230ed8SRasesh Mody 	"fc_tx_ucast_vlan",
2218b230ed8SRasesh Mody 	"fc_tx_mcast_octets",
2228b230ed8SRasesh Mody 	"fc_tx_mcast",
2238b230ed8SRasesh Mody 	"fc_tx_mcast_vlan",
2248b230ed8SRasesh Mody 	"fc_tx_bcast_octets",
2258b230ed8SRasesh Mody 	"fc_tx_bcast",
2268b230ed8SRasesh Mody 	"fc_tx_bcast_vlan",
2278b230ed8SRasesh Mody 	"fc_tx_parity_errors",
2288b230ed8SRasesh Mody 	"fc_tx_timeout",
2298b230ed8SRasesh Mody 	"fc_tx_fid_parity_errors",
2308b230ed8SRasesh Mody };
2318b230ed8SRasesh Mody 
23237dd3482SIvan Vecera #define BNAD_ETHTOOL_STATS_NUM	ARRAY_SIZE(bnad_net_stats_strings)
23337dd3482SIvan Vecera 
2348b230ed8SRasesh Mody static int
bnad_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * cmd)235377fa64fSPhilippe Reynes bnad_get_link_ksettings(struct net_device *netdev,
236377fa64fSPhilippe Reynes 			struct ethtool_link_ksettings *cmd)
2378b230ed8SRasesh Mody {
2387adf9053SErik Ekman 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
2397adf9053SErik Ekman 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
240377fa64fSPhilippe Reynes 
2417adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseCR_Full);
2427adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseSR_Full);
2437adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseLR_Full);
2447adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseCR_Full);
2457adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseSR_Full);
2467adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseLR_Full);
247377fa64fSPhilippe Reynes 	cmd->base.autoneg = AUTONEG_DISABLE;
2487adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
2497adf9053SErik Ekman 	ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
250377fa64fSPhilippe Reynes 	cmd->base.port = PORT_FIBRE;
251377fa64fSPhilippe Reynes 	cmd->base.phy_address = 0;
2528b230ed8SRasesh Mody 
2538b230ed8SRasesh Mody 	if (netif_carrier_ok(netdev)) {
254377fa64fSPhilippe Reynes 		cmd->base.speed = SPEED_10000;
255377fa64fSPhilippe Reynes 		cmd->base.duplex = DUPLEX_FULL;
2568b230ed8SRasesh Mody 	} else {
257377fa64fSPhilippe Reynes 		cmd->base.speed = SPEED_UNKNOWN;
258377fa64fSPhilippe Reynes 		cmd->base.duplex = DUPLEX_UNKNOWN;
2598b230ed8SRasesh Mody 	}
260377fa64fSPhilippe Reynes 
2618b230ed8SRasesh Mody 	return 0;
2628b230ed8SRasesh Mody }
2638b230ed8SRasesh Mody 
2648b230ed8SRasesh Mody static int
bnad_set_link_ksettings(struct net_device * netdev,const struct ethtool_link_ksettings * cmd)265377fa64fSPhilippe Reynes bnad_set_link_ksettings(struct net_device *netdev,
266377fa64fSPhilippe Reynes 			const struct ethtool_link_ksettings *cmd)
2678b230ed8SRasesh Mody {
2688b230ed8SRasesh Mody 	/* 10G full duplex setting supported only */
269377fa64fSPhilippe Reynes 	if (cmd->base.autoneg == AUTONEG_ENABLE)
270377fa64fSPhilippe Reynes 		return -EOPNOTSUPP;
271377fa64fSPhilippe Reynes 
272377fa64fSPhilippe Reynes 	if ((cmd->base.speed == SPEED_10000) &&
273377fa64fSPhilippe Reynes 	    (cmd->base.duplex == DUPLEX_FULL))
2748b230ed8SRasesh Mody 		return 0;
2758b230ed8SRasesh Mody 
2768b230ed8SRasesh Mody 	return -EOPNOTSUPP;
2778b230ed8SRasesh Mody }
2788b230ed8SRasesh Mody 
2798b230ed8SRasesh Mody static void
bnad_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)2808b230ed8SRasesh Mody bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
2818b230ed8SRasesh Mody {
2828b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
2838b230ed8SRasesh Mody 	struct bfa_ioc_attr *ioc_attr;
2848b230ed8SRasesh Mody 	unsigned long flags;
2858b230ed8SRasesh Mody 
286f029c781SWolfram Sang 	strscpy(drvinfo->driver, BNAD_NAME, sizeof(drvinfo->driver));
2878b230ed8SRasesh Mody 
2888b230ed8SRasesh Mody 	ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
2898b230ed8SRasesh Mody 	if (ioc_attr) {
2908b230ed8SRasesh Mody 		spin_lock_irqsave(&bnad->bna_lock, flags);
291078086f3SRasesh Mody 		bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr);
2928b230ed8SRasesh Mody 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
2938b230ed8SRasesh Mody 
294f029c781SWolfram Sang 		strscpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
29568aad78cSRick Jones 			sizeof(drvinfo->fw_version));
2968b230ed8SRasesh Mody 		kfree(ioc_attr);
2978b230ed8SRasesh Mody 	}
2988b230ed8SRasesh Mody 
299f029c781SWolfram Sang 	strscpy(drvinfo->bus_info, pci_name(bnad->pcidev),
30068aad78cSRick Jones 		sizeof(drvinfo->bus_info));
3018b230ed8SRasesh Mody }
3028b230ed8SRasesh Mody 
3038b230ed8SRasesh Mody static void
bnad_get_wol(struct net_device * netdev,struct ethtool_wolinfo * wolinfo)3048b230ed8SRasesh Mody bnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo)
3058b230ed8SRasesh Mody {
3068b230ed8SRasesh Mody 	wolinfo->supported = 0;
3078b230ed8SRasesh Mody 	wolinfo->wolopts = 0;
3088b230ed8SRasesh Mody }
3098b230ed8SRasesh Mody 
bnad_get_coalesce(struct net_device * netdev,struct ethtool_coalesce * coalesce,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)310f3ccfda1SYufeng Mo static int bnad_get_coalesce(struct net_device *netdev,
311f3ccfda1SYufeng Mo 			     struct ethtool_coalesce *coalesce,
312f3ccfda1SYufeng Mo 			     struct kernel_ethtool_coalesce *kernel_coal,
313f3ccfda1SYufeng Mo 			     struct netlink_ext_ack *extack)
3148b230ed8SRasesh Mody {
3158b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
3168b230ed8SRasesh Mody 	unsigned long flags;
3178b230ed8SRasesh Mody 
3188b230ed8SRasesh Mody 	/* Lock rqd. to access bnad->bna_lock */
3198b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
3208b230ed8SRasesh Mody 	coalesce->use_adaptive_rx_coalesce =
3218b230ed8SRasesh Mody 		(bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false;
3228b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
3238b230ed8SRasesh Mody 
3248b230ed8SRasesh Mody 	coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
3258b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT;
3268b230ed8SRasesh Mody 	coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
3278b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT;
3288b230ed8SRasesh Mody 	coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT;
3298b230ed8SRasesh Mody 
3308b230ed8SRasesh Mody 	return 0;
3318b230ed8SRasesh Mody }
3328b230ed8SRasesh Mody 
bnad_set_coalesce(struct net_device * netdev,struct ethtool_coalesce * coalesce,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)333f3ccfda1SYufeng Mo static int bnad_set_coalesce(struct net_device *netdev,
334f3ccfda1SYufeng Mo 			     struct ethtool_coalesce *coalesce,
335f3ccfda1SYufeng Mo 			     struct kernel_ethtool_coalesce *kernel_coal,
336f3ccfda1SYufeng Mo 			     struct netlink_ext_ack *extack)
3378b230ed8SRasesh Mody {
3388b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
3398b230ed8SRasesh Mody 	unsigned long flags;
340a2122d95SRasesh Mody 	int to_del = 0;
3418b230ed8SRasesh Mody 
3428b230ed8SRasesh Mody 	if (coalesce->rx_coalesce_usecs == 0 ||
3438b230ed8SRasesh Mody 	    coalesce->rx_coalesce_usecs >
3448b230ed8SRasesh Mody 	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
3458b230ed8SRasesh Mody 		return -EINVAL;
3468b230ed8SRasesh Mody 
3478b230ed8SRasesh Mody 	if (coalesce->tx_coalesce_usecs == 0 ||
3488b230ed8SRasesh Mody 	    coalesce->tx_coalesce_usecs >
3498b230ed8SRasesh Mody 	    BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT)
3508b230ed8SRasesh Mody 		return -EINVAL;
3518b230ed8SRasesh Mody 
3528b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
3538b230ed8SRasesh Mody 	/*
3548b230ed8SRasesh Mody 	 * Do not need to store rx_coalesce_usecs here
3558b230ed8SRasesh Mody 	 * Every time DIM is disabled, we can get it from the
3568b230ed8SRasesh Mody 	 * stack.
3578b230ed8SRasesh Mody 	 */
3588b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
3598b230ed8SRasesh Mody 	if (coalesce->use_adaptive_rx_coalesce) {
3608b230ed8SRasesh Mody 		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) {
3618b230ed8SRasesh Mody 			bnad->cfg_flags |= BNAD_CF_DIM_ENABLED;
3628b230ed8SRasesh Mody 			bnad_dim_timer_start(bnad);
3638b230ed8SRasesh Mody 		}
3648b230ed8SRasesh Mody 	} else {
3658b230ed8SRasesh Mody 		if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) {
3668b230ed8SRasesh Mody 			bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED;
367a2122d95SRasesh Mody 			if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED &&
368a2122d95SRasesh Mody 			    test_bit(BNAD_RF_DIM_TIMER_RUNNING,
369a2122d95SRasesh Mody 			    &bnad->run_flags)) {
3708b230ed8SRasesh Mody 				clear_bit(BNAD_RF_DIM_TIMER_RUNNING,
3718b230ed8SRasesh Mody 							&bnad->run_flags);
372a2122d95SRasesh Mody 				to_del = 1;
373a2122d95SRasesh Mody 			}
3748b230ed8SRasesh Mody 			spin_unlock_irqrestore(&bnad->bna_lock, flags);
375a2122d95SRasesh Mody 			if (to_del)
376*8fa7292fSThomas Gleixner 				timer_delete_sync(&bnad->dim_timer);
3778b230ed8SRasesh Mody 			spin_lock_irqsave(&bnad->bna_lock, flags);
3788b230ed8SRasesh Mody 			bnad_rx_coalescing_timeo_set(bnad);
3798b230ed8SRasesh Mody 		}
3808b230ed8SRasesh Mody 	}
3818b230ed8SRasesh Mody 	if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs /
3828b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT) {
3838b230ed8SRasesh Mody 		bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
3848b230ed8SRasesh Mody 						BFI_COALESCING_TIMER_UNIT;
3858b230ed8SRasesh Mody 		bnad_tx_coalescing_timeo_set(bnad);
3868b230ed8SRasesh Mody 	}
3878b230ed8SRasesh Mody 
3888b230ed8SRasesh Mody 	if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs /
3898b230ed8SRasesh Mody 					BFI_COALESCING_TIMER_UNIT) {
3908b230ed8SRasesh Mody 		bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
3918b230ed8SRasesh Mody 						BFI_COALESCING_TIMER_UNIT;
3928b230ed8SRasesh Mody 
3938b230ed8SRasesh Mody 		if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED))
3948b230ed8SRasesh Mody 			bnad_rx_coalescing_timeo_set(bnad);
3958b230ed8SRasesh Mody 
3968b230ed8SRasesh Mody 	}
3978b230ed8SRasesh Mody 
3988b230ed8SRasesh Mody 	/* Add Tx Inter-pkt DMA count?  */
3998b230ed8SRasesh Mody 
4008b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
4018b230ed8SRasesh Mody 
4028b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
4038b230ed8SRasesh Mody 	return 0;
4048b230ed8SRasesh Mody }
4058b230ed8SRasesh Mody 
4068b230ed8SRasesh Mody static void
bnad_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ringparam,struct kernel_ethtool_ringparam * kernel_ringparam,struct netlink_ext_ack * extack)4078b230ed8SRasesh Mody bnad_get_ringparam(struct net_device *netdev,
40874624944SHao Chen 		   struct ethtool_ringparam *ringparam,
40974624944SHao Chen 		   struct kernel_ethtool_ringparam *kernel_ringparam,
41074624944SHao Chen 		   struct netlink_ext_ack *extack)
4118b230ed8SRasesh Mody {
4128b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
4138b230ed8SRasesh Mody 
41441eb5ba4SRasesh Mody 	ringparam->rx_max_pending = BNAD_MAX_RXQ_DEPTH;
41541eb5ba4SRasesh Mody 	ringparam->tx_max_pending = BNAD_MAX_TXQ_DEPTH;
4168b230ed8SRasesh Mody 
4178b230ed8SRasesh Mody 	ringparam->rx_pending = bnad->rxq_depth;
4188b230ed8SRasesh Mody 	ringparam->tx_pending = bnad->txq_depth;
4198b230ed8SRasesh Mody }
4208b230ed8SRasesh Mody 
4218b230ed8SRasesh Mody static int
bnad_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ringparam,struct kernel_ethtool_ringparam * kernel_ringparam,struct netlink_ext_ack * extack)4228b230ed8SRasesh Mody bnad_set_ringparam(struct net_device *netdev,
42374624944SHao Chen 		   struct ethtool_ringparam *ringparam,
42474624944SHao Chen 		   struct kernel_ethtool_ringparam *kernel_ringparam,
42574624944SHao Chen 		   struct netlink_ext_ack *extack)
4268b230ed8SRasesh Mody {
4278b230ed8SRasesh Mody 	int i, current_err, err = 0;
4288b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
429a2122d95SRasesh Mody 	unsigned long flags;
4308b230ed8SRasesh Mody 
4318b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
4328b230ed8SRasesh Mody 	if (ringparam->rx_pending == bnad->rxq_depth &&
4338b230ed8SRasesh Mody 	    ringparam->tx_pending == bnad->txq_depth) {
4348b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4358b230ed8SRasesh Mody 		return 0;
4368b230ed8SRasesh Mody 	}
4378b230ed8SRasesh Mody 
4388b230ed8SRasesh Mody 	if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
43941eb5ba4SRasesh Mody 	    ringparam->rx_pending > BNAD_MAX_RXQ_DEPTH ||
440a1ac490dSIvan Vecera 	    !is_power_of_2(ringparam->rx_pending)) {
4418b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4428b230ed8SRasesh Mody 		return -EINVAL;
4438b230ed8SRasesh Mody 	}
4448b230ed8SRasesh Mody 	if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
44541eb5ba4SRasesh Mody 	    ringparam->tx_pending > BNAD_MAX_TXQ_DEPTH ||
446a1ac490dSIvan Vecera 	    !is_power_of_2(ringparam->tx_pending)) {
4478b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
4488b230ed8SRasesh Mody 		return -EINVAL;
4498b230ed8SRasesh Mody 	}
4508b230ed8SRasesh Mody 
4518b230ed8SRasesh Mody 	if (ringparam->rx_pending != bnad->rxq_depth) {
4528b230ed8SRasesh Mody 		bnad->rxq_depth = ringparam->rx_pending;
453a2122d95SRasesh Mody 		if (!netif_running(netdev)) {
454a2122d95SRasesh Mody 			mutex_unlock(&bnad->conf_mutex);
455a2122d95SRasesh Mody 			return 0;
456a2122d95SRasesh Mody 		}
457a2122d95SRasesh Mody 
4588b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_rx; i++) {
4598b230ed8SRasesh Mody 			if (!bnad->rx_info[i].rx)
4608b230ed8SRasesh Mody 				continue;
461b3cc6e88SJing Huang 			bnad_destroy_rx(bnad, i);
4628b230ed8SRasesh Mody 			current_err = bnad_setup_rx(bnad, i);
4638b230ed8SRasesh Mody 			if (current_err && !err)
4648b230ed8SRasesh Mody 				err = current_err;
465a2122d95SRasesh Mody 		}
466a2122d95SRasesh Mody 
467a2122d95SRasesh Mody 		if (!err && bnad->rx_info[0].rx) {
468a2122d95SRasesh Mody 			/* restore rx configuration */
4693fb9852fSRasesh Mody 			bnad_restore_vlans(bnad, 0);
470a2122d95SRasesh Mody 			bnad_enable_default_bcast(bnad);
471a2122d95SRasesh Mody 			spin_lock_irqsave(&bnad->bna_lock, flags);
472a2122d95SRasesh Mody 			bnad_mac_addr_set_locked(bnad, netdev->dev_addr);
473a2122d95SRasesh Mody 			spin_unlock_irqrestore(&bnad->bna_lock, flags);
4743fb9852fSRasesh Mody 			bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI |
4753fb9852fSRasesh Mody 					     BNAD_CF_PROMISC);
476a2122d95SRasesh Mody 			bnad_set_rx_mode(netdev);
4778b230ed8SRasesh Mody 		}
4788b230ed8SRasesh Mody 	}
4798b230ed8SRasesh Mody 	if (ringparam->tx_pending != bnad->txq_depth) {
4808b230ed8SRasesh Mody 		bnad->txq_depth = ringparam->tx_pending;
481a2122d95SRasesh Mody 		if (!netif_running(netdev)) {
482a2122d95SRasesh Mody 			mutex_unlock(&bnad->conf_mutex);
483a2122d95SRasesh Mody 			return 0;
484a2122d95SRasesh Mody 		}
485a2122d95SRasesh Mody 
4868b230ed8SRasesh Mody 		for (i = 0; i < bnad->num_tx; i++) {
4878b230ed8SRasesh Mody 			if (!bnad->tx_info[i].tx)
4888b230ed8SRasesh Mody 				continue;
489b3cc6e88SJing Huang 			bnad_destroy_tx(bnad, i);
4908b230ed8SRasesh Mody 			current_err = bnad_setup_tx(bnad, i);
4918b230ed8SRasesh Mody 			if (current_err && !err)
4928b230ed8SRasesh Mody 				err = current_err;
4938b230ed8SRasesh Mody 		}
4948b230ed8SRasesh Mody 	}
4958b230ed8SRasesh Mody 
4968b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
4978b230ed8SRasesh Mody 	return err;
4988b230ed8SRasesh Mody }
4998b230ed8SRasesh Mody 
5008b230ed8SRasesh Mody static void
bnad_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pauseparam)5018b230ed8SRasesh Mody bnad_get_pauseparam(struct net_device *netdev,
5028b230ed8SRasesh Mody 		    struct ethtool_pauseparam *pauseparam)
5038b230ed8SRasesh Mody {
5048b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5058b230ed8SRasesh Mody 
5068b230ed8SRasesh Mody 	pauseparam->autoneg = 0;
507078086f3SRasesh Mody 	pauseparam->rx_pause = bnad->bna.enet.pause_config.rx_pause;
508078086f3SRasesh Mody 	pauseparam->tx_pause = bnad->bna.enet.pause_config.tx_pause;
5098b230ed8SRasesh Mody }
5108b230ed8SRasesh Mody 
5118b230ed8SRasesh Mody static int
bnad_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pauseparam)5128b230ed8SRasesh Mody bnad_set_pauseparam(struct net_device *netdev,
5138b230ed8SRasesh Mody 		    struct ethtool_pauseparam *pauseparam)
5148b230ed8SRasesh Mody {
5158b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
5168b230ed8SRasesh Mody 	struct bna_pause_config pause_config;
5178b230ed8SRasesh Mody 	unsigned long flags;
5188b230ed8SRasesh Mody 
5198b230ed8SRasesh Mody 	if (pauseparam->autoneg == AUTONEG_ENABLE)
5208b230ed8SRasesh Mody 		return -EINVAL;
5218b230ed8SRasesh Mody 
5228b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
523078086f3SRasesh Mody 	if (pauseparam->rx_pause != bnad->bna.enet.pause_config.rx_pause ||
524078086f3SRasesh Mody 	    pauseparam->tx_pause != bnad->bna.enet.pause_config.tx_pause) {
5258b230ed8SRasesh Mody 		pause_config.rx_pause = pauseparam->rx_pause;
5268b230ed8SRasesh Mody 		pause_config.tx_pause = pauseparam->tx_pause;
5278b230ed8SRasesh Mody 		spin_lock_irqsave(&bnad->bna_lock, flags);
5281f9883e0SIvan Vecera 		bna_enet_pause_config(&bnad->bna.enet, &pause_config);
5298b230ed8SRasesh Mody 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
5308b230ed8SRasesh Mody 	}
5318b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
5328b230ed8SRasesh Mody 	return 0;
5338b230ed8SRasesh Mody }
5348b230ed8SRasesh Mody 
bnad_get_txf_strings(u8 ** string,int f_num)535b82e8118SAlexander Duyck static void bnad_get_txf_strings(u8 **string, int f_num)
536b82e8118SAlexander Duyck {
537b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_ucast_octets", f_num);
538b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_ucast", f_num);
539b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_ucast_vlan", f_num);
540b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_mcast_octets", f_num);
541b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_mcast", f_num);
542b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_mcast_vlan", f_num);
543b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_bcast_octets", f_num);
544b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_bcast", f_num);
545b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_bcast_vlan", f_num);
546b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_errors", f_num);
547b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_filter_vlan", f_num);
548b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txf%d_filter_mac_sa", f_num);
549b82e8118SAlexander Duyck }
550b82e8118SAlexander Duyck 
bnad_get_rxf_strings(u8 ** string,int f_num)551b82e8118SAlexander Duyck static void bnad_get_rxf_strings(u8 **string, int f_num)
552b82e8118SAlexander Duyck {
553b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_ucast_octets", f_num);
554b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_ucast", f_num);
555b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_ucast_vlan", f_num);
556b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_mcast_octets", f_num);
557b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_mcast", f_num);
558b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_mcast_vlan", f_num);
559b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_bcast_octets", f_num);
560b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_bcast", f_num);
561b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_bcast_vlan", f_num);
562b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxf%d_frame_drops", f_num);
563b82e8118SAlexander Duyck }
564b82e8118SAlexander Duyck 
bnad_get_cq_strings(u8 ** string,int q_num)565b82e8118SAlexander Duyck static void bnad_get_cq_strings(u8 **string, int q_num)
566b82e8118SAlexander Duyck {
567b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_producer_index", q_num);
568b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_consumer_index", q_num);
569b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_hw_producer_index", q_num);
570b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_intr", q_num);
571b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_poll", q_num);
572b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_schedule", q_num);
573b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_keep_poll", q_num);
574b82e8118SAlexander Duyck 	ethtool_sprintf(string, "cq%d_complete", q_num);
575b82e8118SAlexander Duyck }
576b82e8118SAlexander Duyck 
bnad_get_rxq_strings(u8 ** string,int q_num)577b82e8118SAlexander Duyck static void bnad_get_rxq_strings(u8 **string, int q_num)
578b82e8118SAlexander Duyck {
579b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_packets", q_num);
580b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_bytes", q_num);
581b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_packets_with_error", q_num);
582b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_allocbuf_failed", q_num);
583b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_mapbuf_failed", q_num);
584b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_producer_index", q_num);
585b82e8118SAlexander Duyck 	ethtool_sprintf(string, "rxq%d_consumer_index", q_num);
586b82e8118SAlexander Duyck }
587b82e8118SAlexander Duyck 
bnad_get_txq_strings(u8 ** string,int q_num)588b82e8118SAlexander Duyck static void bnad_get_txq_strings(u8 **string, int q_num)
589b82e8118SAlexander Duyck {
590b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txq%d_packets", q_num);
591b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txq%d_bytes", q_num);
592b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txq%d_producer_index", q_num);
593b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txq%d_consumer_index", q_num);
594b82e8118SAlexander Duyck 	ethtool_sprintf(string, "txq%d_hw_consumer_index", q_num);
595b82e8118SAlexander Duyck }
596b82e8118SAlexander Duyck 
5978b230ed8SRasesh Mody static void
bnad_get_strings(struct net_device * netdev,u32 stringset,u8 * string)5988b230ed8SRasesh Mody bnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string)
5998b230ed8SRasesh Mody {
6008b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
6018b230ed8SRasesh Mody 	int i, j, q_num;
602078086f3SRasesh Mody 	u32 bmap;
6038b230ed8SRasesh Mody 
604b82e8118SAlexander Duyck 	if (stringset != ETH_SS_STATS)
605b82e8118SAlexander Duyck 		return;
606b82e8118SAlexander Duyck 
6078b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
6088b230ed8SRasesh Mody 
6098b230ed8SRasesh Mody 	for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
610b82e8118SAlexander Duyck 		BUG_ON(!(strlen(bnad_net_stats_strings[i]) < ETH_GSTRING_LEN));
611e403cfffSjustinstitt@google.com 		ethtool_puts(&string, bnad_net_stats_strings[i]);
6128b230ed8SRasesh Mody 	}
613b82e8118SAlexander Duyck 
614078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
615078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
616b82e8118SAlexander Duyck 		if (bmap & 1)
617b82e8118SAlexander Duyck 			bnad_get_txf_strings(&string, i);
6188b230ed8SRasesh Mody 		bmap >>= 1;
6198b230ed8SRasesh Mody 	}
6208b230ed8SRasesh Mody 
621078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
622b82e8118SAlexander Duyck 	for (i = 0; bmap; i++, bmap >>= 1) {
623b82e8118SAlexander Duyck 		if (bmap & 1)
624b82e8118SAlexander Duyck 			bnad_get_rxf_strings(&string, i);
6258b230ed8SRasesh Mody 		bmap >>= 1;
6268b230ed8SRasesh Mody 	}
6278b230ed8SRasesh Mody 
6288b230ed8SRasesh Mody 	q_num = 0;
6298b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
6308b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
6318b230ed8SRasesh Mody 			continue;
632b82e8118SAlexander Duyck 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
633b82e8118SAlexander Duyck 			bnad_get_cq_strings(&string, q_num++);
6348b230ed8SRasesh Mody 	}
6358b230ed8SRasesh Mody 
6368b230ed8SRasesh Mody 	q_num = 0;
6378b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
6388b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
6398b230ed8SRasesh Mody 			continue;
6408b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++) {
641b82e8118SAlexander Duyck 			bnad_get_rxq_strings(&string, q_num++);
6428b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
643b82e8118SAlexander Duyck 			    bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
644b82e8118SAlexander Duyck 			    bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
645b82e8118SAlexander Duyck 				bnad_get_rxq_strings(&string, q_num++);
6468b230ed8SRasesh Mody 		}
6478b230ed8SRasesh Mody 	}
6488b230ed8SRasesh Mody 
6498b230ed8SRasesh Mody 	q_num = 0;
6508b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
6518b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
6528b230ed8SRasesh Mody 			continue;
653b82e8118SAlexander Duyck 		for (j = 0; j < bnad->num_txq_per_tx; j++)
654b82e8118SAlexander Duyck 			bnad_get_txq_strings(&string, q_num++);
6558b230ed8SRasesh Mody 	}
6568b230ed8SRasesh Mody 
6578b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
6588b230ed8SRasesh Mody }
6598b230ed8SRasesh Mody 
6608b230ed8SRasesh Mody static int
bnad_get_stats_count_locked(struct net_device * netdev)6618b230ed8SRasesh Mody bnad_get_stats_count_locked(struct net_device *netdev)
6628b230ed8SRasesh Mody {
6638b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
664a2122d95SRasesh Mody 	int i, j, count = 0, rxf_active_num = 0, txf_active_num = 0;
665078086f3SRasesh Mody 	u32 bmap;
6668b230ed8SRasesh Mody 
667078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
668078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
6698b230ed8SRasesh Mody 		if (bmap & 1)
6708b230ed8SRasesh Mody 			txf_active_num++;
6718b230ed8SRasesh Mody 		bmap >>= 1;
6728b230ed8SRasesh Mody 	}
673078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
674078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
6758b230ed8SRasesh Mody 		if (bmap & 1)
6768b230ed8SRasesh Mody 			rxf_active_num++;
6778b230ed8SRasesh Mody 		bmap >>= 1;
6788b230ed8SRasesh Mody 	}
6798b230ed8SRasesh Mody 	count = BNAD_ETHTOOL_STATS_NUM +
6808b230ed8SRasesh Mody 		txf_active_num * BNAD_NUM_TXF_COUNTERS +
6818b230ed8SRasesh Mody 		rxf_active_num * BNAD_NUM_RXF_COUNTERS;
6828b230ed8SRasesh Mody 
6838b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
6848b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
6858b230ed8SRasesh Mody 			continue;
6868b230ed8SRasesh Mody 		count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS;
6878b230ed8SRasesh Mody 		count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS;
6888b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
6898b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
6908b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
6918b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq)
6928b230ed8SRasesh Mody 				count +=  BNAD_NUM_RXQ_COUNTERS;
6938b230ed8SRasesh Mody 	}
6948b230ed8SRasesh Mody 
6958b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
6968b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
6978b230ed8SRasesh Mody 			continue;
6988b230ed8SRasesh Mody 		count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS;
6998b230ed8SRasesh Mody 	}
7008b230ed8SRasesh Mody 	return count;
7018b230ed8SRasesh Mody }
7028b230ed8SRasesh Mody 
7038b230ed8SRasesh Mody static int
bnad_per_q_stats_fill(struct bnad * bnad,u64 * buf,int bi)7048b230ed8SRasesh Mody bnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi)
7058b230ed8SRasesh Mody {
7068b230ed8SRasesh Mody 	int i, j;
7078b230ed8SRasesh Mody 	struct bna_rcb *rcb = NULL;
7088b230ed8SRasesh Mody 	struct bna_tcb *tcb = NULL;
7098b230ed8SRasesh Mody 
7108b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7118b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7128b230ed8SRasesh Mody 			continue;
7138b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7148b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb &&
7158b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
7168b230ed8SRasesh Mody 				bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) {
7178b230ed8SRasesh Mody 				buf[bi++] = bnad->rx_info[i].rx_ctrl[j].
7188b230ed8SRasesh Mody 						ccb->producer_index;
7198b230ed8SRasesh Mody 				buf[bi++] = 0; /* ccb->consumer_index */
7208b230ed8SRasesh Mody 				buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j].
7218b230ed8SRasesh Mody 						ccb->hw_producer_index);
722a2122d95SRasesh Mody 
723a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
724a2122d95SRasesh Mody 						rx_ctrl[j].rx_intr_ctr;
725a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
726a2122d95SRasesh Mody 						rx_ctrl[j].rx_poll_ctr;
727a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
728a2122d95SRasesh Mody 						rx_ctrl[j].rx_schedule;
729a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
730a2122d95SRasesh Mody 						rx_ctrl[j].rx_keep_poll;
731a2122d95SRasesh Mody 				buf[bi++] = bnad->rx_info[i].
732a2122d95SRasesh Mody 						rx_ctrl[j].rx_complete;
7338b230ed8SRasesh Mody 			}
7348b230ed8SRasesh Mody 	}
7358b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_rx; i++) {
7368b230ed8SRasesh Mody 		if (!bnad->rx_info[i].rx)
7378b230ed8SRasesh Mody 			continue;
7388b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_rxp_per_rx; j++)
7398b230ed8SRasesh Mody 			if (bnad->rx_info[i].rx_ctrl[j].ccb) {
7408b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] &&
7418b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
7428b230ed8SRasesh Mody 					rcb[0]->rxq) {
7438b230ed8SRasesh Mody 					rcb = bnad->rx_info[i].rx_ctrl[j].
7448b230ed8SRasesh Mody 							ccb->rcb[0];
7458b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_packets;
7468b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_bytes;
7478b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
7488b230ed8SRasesh Mody 							rx_packets_with_error;
7498b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
7508b230ed8SRasesh Mody 							rxbuf_alloc_failed;
751ba5ca784SIvan Vecera 					buf[bi++] = rcb->rxq->rxbuf_map_failed;
7528b230ed8SRasesh Mody 					buf[bi++] = rcb->producer_index;
7538b230ed8SRasesh Mody 					buf[bi++] = rcb->consumer_index;
7548b230ed8SRasesh Mody 				}
7558b230ed8SRasesh Mody 				if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] &&
7568b230ed8SRasesh Mody 					bnad->rx_info[i].rx_ctrl[j].ccb->
7578b230ed8SRasesh Mody 					rcb[1]->rxq) {
7588b230ed8SRasesh Mody 					rcb = bnad->rx_info[i].rx_ctrl[j].
7598b230ed8SRasesh Mody 								ccb->rcb[1];
7608b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_packets;
7618b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->rx_bytes;
7628b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
7638b230ed8SRasesh Mody 							rx_packets_with_error;
7648b230ed8SRasesh Mody 					buf[bi++] = rcb->rxq->
7658b230ed8SRasesh Mody 							rxbuf_alloc_failed;
766ba5ca784SIvan Vecera 					buf[bi++] = rcb->rxq->rxbuf_map_failed;
7678b230ed8SRasesh Mody 					buf[bi++] = rcb->producer_index;
7688b230ed8SRasesh Mody 					buf[bi++] = rcb->consumer_index;
7698b230ed8SRasesh Mody 				}
7708b230ed8SRasesh Mody 			}
7718b230ed8SRasesh Mody 	}
7728b230ed8SRasesh Mody 
7738b230ed8SRasesh Mody 	for (i = 0; i < bnad->num_tx; i++) {
7748b230ed8SRasesh Mody 		if (!bnad->tx_info[i].tx)
7758b230ed8SRasesh Mody 			continue;
7768b230ed8SRasesh Mody 		for (j = 0; j < bnad->num_txq_per_tx; j++)
7778b230ed8SRasesh Mody 			if (bnad->tx_info[i].tcb[j] &&
7788b230ed8SRasesh Mody 				bnad->tx_info[i].tcb[j]->txq) {
7798b230ed8SRasesh Mody 				tcb = bnad->tx_info[i].tcb[j];
7808b230ed8SRasesh Mody 				buf[bi++] = tcb->txq->tx_packets;
7818b230ed8SRasesh Mody 				buf[bi++] = tcb->txq->tx_bytes;
7828b230ed8SRasesh Mody 				buf[bi++] = tcb->producer_index;
7838b230ed8SRasesh Mody 				buf[bi++] = tcb->consumer_index;
7848b230ed8SRasesh Mody 				buf[bi++] = *(tcb->hw_consumer_index);
7858b230ed8SRasesh Mody 			}
7868b230ed8SRasesh Mody 	}
7878b230ed8SRasesh Mody 
7888b230ed8SRasesh Mody 	return bi;
7898b230ed8SRasesh Mody }
7908b230ed8SRasesh Mody 
7918b230ed8SRasesh Mody static void
bnad_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * buf)7928b230ed8SRasesh Mody bnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats,
7938b230ed8SRasesh Mody 		       u64 *buf)
7948b230ed8SRasesh Mody {
7958b230ed8SRasesh Mody 	struct bnad *bnad = netdev_priv(netdev);
79637dd3482SIvan Vecera 	int i, j, bi = 0;
797250e061eSEric Dumazet 	unsigned long flags;
79837dd3482SIvan Vecera 	struct rtnl_link_stats64 net_stats64;
7998b230ed8SRasesh Mody 	u64 *stats64;
800078086f3SRasesh Mody 	u32 bmap;
8018b230ed8SRasesh Mody 
8028b230ed8SRasesh Mody 	mutex_lock(&bnad->conf_mutex);
8038b230ed8SRasesh Mody 	if (bnad_get_stats_count_locked(netdev) != stats->n_stats) {
8048b230ed8SRasesh Mody 		mutex_unlock(&bnad->conf_mutex);
8058b230ed8SRasesh Mody 		return;
8068b230ed8SRasesh Mody 	}
8078b230ed8SRasesh Mody 
8088b230ed8SRasesh Mody 	/*
8098b230ed8SRasesh Mody 	 * Used bna_lock to sync reads from bna_stats, which is written
8108b230ed8SRasesh Mody 	 * under the same lock
8118b230ed8SRasesh Mody 	 */
8128b230ed8SRasesh Mody 	spin_lock_irqsave(&bnad->bna_lock, flags);
8138b230ed8SRasesh Mody 
81437dd3482SIvan Vecera 	memset(&net_stats64, 0, sizeof(net_stats64));
81537dd3482SIvan Vecera 	bnad_netdev_qstats_fill(bnad, &net_stats64);
81637dd3482SIvan Vecera 	bnad_netdev_hwstats_fill(bnad, &net_stats64);
8178b230ed8SRasesh Mody 
81837dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_packets;
81937dd3482SIvan Vecera 	buf[bi++] = net_stats64.tx_packets;
82037dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_bytes;
82137dd3482SIvan Vecera 	buf[bi++] = net_stats64.tx_bytes;
82237dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_errors;
82337dd3482SIvan Vecera 	buf[bi++] = net_stats64.tx_errors;
82437dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_dropped;
82537dd3482SIvan Vecera 	buf[bi++] = net_stats64.tx_dropped;
82637dd3482SIvan Vecera 	buf[bi++] = net_stats64.multicast;
82737dd3482SIvan Vecera 	buf[bi++] = net_stats64.collisions;
82837dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_length_errors;
82937dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_crc_errors;
83037dd3482SIvan Vecera 	buf[bi++] = net_stats64.rx_frame_errors;
83137dd3482SIvan Vecera 	buf[bi++] = net_stats64.tx_fifo_errors;
8328b230ed8SRasesh Mody 
833f7c0fa4cSRasesh Mody 	/* Get netif_queue_stopped from stack */
834f7c0fa4cSRasesh Mody 	bnad->stats.drv_stats.netif_queue_stopped = netif_queue_stopped(netdev);
835f7c0fa4cSRasesh Mody 
8368b230ed8SRasesh Mody 	/* Fill driver stats into ethtool buffers */
8378b230ed8SRasesh Mody 	stats64 = (u64 *)&bnad->stats.drv_stats;
8388b230ed8SRasesh Mody 	for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++)
8398b230ed8SRasesh Mody 		buf[bi++] = stats64[i];
8408b230ed8SRasesh Mody 
8418b230ed8SRasesh Mody 	/* Fill hardware stats excluding the rxf/txf into ethtool bufs */
842078086f3SRasesh Mody 	stats64 = (u64 *) &bnad->stats.bna_stats->hw_stats;
8438b230ed8SRasesh Mody 	for (i = 0;
844078086f3SRasesh Mody 	     i < offsetof(struct bfi_enet_stats, rxf_stats[0]) /
845078086f3SRasesh Mody 		sizeof(u64);
8468b230ed8SRasesh Mody 	     i++)
8478b230ed8SRasesh Mody 		buf[bi++] = stats64[i];
8488b230ed8SRasesh Mody 
8498b230ed8SRasesh Mody 	/* Fill txf stats into ethtool buffers */
850078086f3SRasesh Mody 	bmap = bna_tx_rid_mask(&bnad->bna);
851078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
8528b230ed8SRasesh Mody 		if (bmap & 1) {
8538b230ed8SRasesh Mody 			stats64 = (u64 *)&bnad->stats.bna_stats->
854078086f3SRasesh Mody 						hw_stats.txf_stats[i];
855078086f3SRasesh Mody 			for (j = 0; j < sizeof(struct bfi_enet_stats_txf) /
8568b230ed8SRasesh Mody 					sizeof(u64); j++)
8578b230ed8SRasesh Mody 				buf[bi++] = stats64[j];
8588b230ed8SRasesh Mody 		}
8598b230ed8SRasesh Mody 		bmap >>= 1;
8608b230ed8SRasesh Mody 	}
8618b230ed8SRasesh Mody 
8628b230ed8SRasesh Mody 	/*  Fill rxf stats into ethtool buffers */
863078086f3SRasesh Mody 	bmap = bna_rx_rid_mask(&bnad->bna);
864078086f3SRasesh Mody 	for (i = 0; bmap; i++) {
8658b230ed8SRasesh Mody 		if (bmap & 1) {
8668b230ed8SRasesh Mody 			stats64 = (u64 *)&bnad->stats.bna_stats->
867078086f3SRasesh Mody 						hw_stats.rxf_stats[i];
868078086f3SRasesh Mody 			for (j = 0; j < sizeof(struct bfi_enet_stats_rxf) /
8698b230ed8SRasesh Mody 					sizeof(u64); j++)
8708b230ed8SRasesh Mody 				buf[bi++] = stats64[j];
8718b230ed8SRasesh Mody 		}
8728b230ed8SRasesh Mody 		bmap >>= 1;
8738b230ed8SRasesh Mody 	}
8748b230ed8SRasesh Mody 
8758b230ed8SRasesh Mody 	/* Fill per Q stats into ethtool buffers */
8768b230ed8SRasesh Mody 	bi = bnad_per_q_stats_fill(bnad, buf, bi);
8778b230ed8SRasesh Mody 
8788b230ed8SRasesh Mody 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
8798b230ed8SRasesh Mody 
8808b230ed8SRasesh Mody 	mutex_unlock(&bnad->conf_mutex);
8818b230ed8SRasesh Mody }
8828b230ed8SRasesh Mody 
8838b230ed8SRasesh Mody static int
bnad_get_sset_count(struct net_device * netdev,int sset)8848b230ed8SRasesh Mody bnad_get_sset_count(struct net_device *netdev, int sset)
8858b230ed8SRasesh Mody {
8868b230ed8SRasesh Mody 	switch (sset) {
8878b230ed8SRasesh Mody 	case ETH_SS_STATS:
8888b230ed8SRasesh Mody 		return bnad_get_stats_count_locked(netdev);
8898b230ed8SRasesh Mody 	default:
8908b230ed8SRasesh Mody 		return -EOPNOTSUPP;
8918b230ed8SRasesh Mody 	}
8928b230ed8SRasesh Mody }
8938b230ed8SRasesh Mody 
89472a9730bSKrishna Gudipati static u32
bnad_get_flash_partition_by_offset(struct bnad * bnad,u32 offset,u32 * base_offset)89572a9730bSKrishna Gudipati bnad_get_flash_partition_by_offset(struct bnad *bnad, u32 offset,
89672a9730bSKrishna Gudipati 				u32 *base_offset)
89772a9730bSKrishna Gudipati {
89872a9730bSKrishna Gudipati 	struct bfa_flash_attr *flash_attr;
89972a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
90072a9730bSKrishna Gudipati 	u32 i, flash_part = 0, ret;
90172a9730bSKrishna Gudipati 	unsigned long flags = 0;
90272a9730bSKrishna Gudipati 
90372a9730bSKrishna Gudipati 	flash_attr = kzalloc(sizeof(struct bfa_flash_attr), GFP_KERNEL);
90472a9730bSKrishna Gudipati 	if (!flash_attr)
905027a3b61SDan Carpenter 		return 0;
90672a9730bSKrishna Gudipati 
90772a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
90872a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
90972a9730bSKrishna Gudipati 
91072a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
91172a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
91272a9730bSKrishna Gudipati 	ret = bfa_nw_flash_get_attr(&bnad->bna.flash, flash_attr,
91372a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
91472a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
91572a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
91672a9730bSKrishna Gudipati 		kfree(flash_attr);
917027a3b61SDan Carpenter 		return 0;
91872a9730bSKrishna Gudipati 	}
91972a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
92072a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
92172a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
92272a9730bSKrishna Gudipati 
92372a9730bSKrishna Gudipati 	/* Check for the flash type & base offset value */
92472a9730bSKrishna Gudipati 	if (ret == BFA_STATUS_OK) {
92572a9730bSKrishna Gudipati 		for (i = 0; i < flash_attr->npart; i++) {
92672a9730bSKrishna Gudipati 			if (offset >= flash_attr->part[i].part_off &&
92772a9730bSKrishna Gudipati 			    offset < (flash_attr->part[i].part_off +
92872a9730bSKrishna Gudipati 				      flash_attr->part[i].part_size)) {
92972a9730bSKrishna Gudipati 				flash_part = flash_attr->part[i].part_type;
93072a9730bSKrishna Gudipati 				*base_offset = flash_attr->part[i].part_off;
93172a9730bSKrishna Gudipati 				break;
93272a9730bSKrishna Gudipati 			}
93372a9730bSKrishna Gudipati 		}
93472a9730bSKrishna Gudipati 	}
93572a9730bSKrishna Gudipati 	kfree(flash_attr);
93672a9730bSKrishna Gudipati 	return flash_part;
93772a9730bSKrishna Gudipati }
93872a9730bSKrishna Gudipati 
93972a9730bSKrishna Gudipati static int
bnad_get_eeprom_len(struct net_device * netdev)94072a9730bSKrishna Gudipati bnad_get_eeprom_len(struct net_device *netdev)
94172a9730bSKrishna Gudipati {
94272a9730bSKrishna Gudipati 	return BFA_TOTAL_FLASH_SIZE;
94372a9730bSKrishna Gudipati }
94472a9730bSKrishna Gudipati 
94572a9730bSKrishna Gudipati static int
bnad_get_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)94672a9730bSKrishna Gudipati bnad_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
94772a9730bSKrishna Gudipati 		u8 *bytes)
94872a9730bSKrishna Gudipati {
94972a9730bSKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
95072a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
95172a9730bSKrishna Gudipati 	u32 flash_part = 0, base_offset = 0;
95272a9730bSKrishna Gudipati 	unsigned long flags = 0;
95372a9730bSKrishna Gudipati 	int ret = 0;
95472a9730bSKrishna Gudipati 
955dabf24d1SIvan Vecera 	/* Fill the magic value */
956dabf24d1SIvan Vecera 	eeprom->magic = bnad->pcidev->vendor | (bnad->pcidev->device << 16);
95772a9730bSKrishna Gudipati 
95872a9730bSKrishna Gudipati 	/* Query the flash partition based on the offset */
95972a9730bSKrishna Gudipati 	flash_part = bnad_get_flash_partition_by_offset(bnad,
96072a9730bSKrishna Gudipati 				eeprom->offset, &base_offset);
961027a3b61SDan Carpenter 	if (flash_part == 0)
96272a9730bSKrishna Gudipati 		return -EFAULT;
96372a9730bSKrishna Gudipati 
96472a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
96572a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
96672a9730bSKrishna Gudipati 
96772a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
96872a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
96972a9730bSKrishna Gudipati 	ret = bfa_nw_flash_read_part(&bnad->bna.flash, flash_part,
97072a9730bSKrishna Gudipati 				bnad->id, bytes, eeprom->len,
97172a9730bSKrishna Gudipati 				eeprom->offset - base_offset,
97272a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
97372a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
97472a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
97572a9730bSKrishna Gudipati 		goto done;
97672a9730bSKrishna Gudipati 	}
97772a9730bSKrishna Gudipati 
97872a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
97972a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
98072a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
98172a9730bSKrishna Gudipati done:
98272a9730bSKrishna Gudipati 	return ret;
98372a9730bSKrishna Gudipati }
98472a9730bSKrishna Gudipati 
98572a9730bSKrishna Gudipati static int
bnad_set_eeprom(struct net_device * netdev,struct ethtool_eeprom * eeprom,u8 * bytes)98672a9730bSKrishna Gudipati bnad_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
98772a9730bSKrishna Gudipati 		u8 *bytes)
98872a9730bSKrishna Gudipati {
98972a9730bSKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
99072a9730bSKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
99172a9730bSKrishna Gudipati 	u32 flash_part = 0, base_offset = 0;
99272a9730bSKrishna Gudipati 	unsigned long flags = 0;
99372a9730bSKrishna Gudipati 	int ret = 0;
99472a9730bSKrishna Gudipati 
99572a9730bSKrishna Gudipati 	/* Check if the flash update request is valid */
99672a9730bSKrishna Gudipati 	if (eeprom->magic != (bnad->pcidev->vendor |
99772a9730bSKrishna Gudipati 			     (bnad->pcidev->device << 16)))
99872a9730bSKrishna Gudipati 		return -EINVAL;
99972a9730bSKrishna Gudipati 
100072a9730bSKrishna Gudipati 	/* Query the flash partition based on the offset */
100172a9730bSKrishna Gudipati 	flash_part = bnad_get_flash_partition_by_offset(bnad,
100272a9730bSKrishna Gudipati 				eeprom->offset, &base_offset);
1003027a3b61SDan Carpenter 	if (flash_part == 0)
100472a9730bSKrishna Gudipati 		return -EFAULT;
100572a9730bSKrishna Gudipati 
100672a9730bSKrishna Gudipati 	fcomp.bnad = bnad;
100772a9730bSKrishna Gudipati 	fcomp.comp_status = 0;
100872a9730bSKrishna Gudipati 
100972a9730bSKrishna Gudipati 	init_completion(&fcomp.comp);
101072a9730bSKrishna Gudipati 	spin_lock_irqsave(&bnad->bna_lock, flags);
101172a9730bSKrishna Gudipati 	ret = bfa_nw_flash_update_part(&bnad->bna.flash, flash_part,
101272a9730bSKrishna Gudipati 				bnad->id, bytes, eeprom->len,
101372a9730bSKrishna Gudipati 				eeprom->offset - base_offset,
101472a9730bSKrishna Gudipati 				bnad_cb_completion, &fcomp);
101572a9730bSKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
101672a9730bSKrishna Gudipati 		spin_unlock_irqrestore(&bnad->bna_lock, flags);
101772a9730bSKrishna Gudipati 		goto done;
101872a9730bSKrishna Gudipati 	}
101972a9730bSKrishna Gudipati 
102072a9730bSKrishna Gudipati 	spin_unlock_irqrestore(&bnad->bna_lock, flags);
102172a9730bSKrishna Gudipati 	wait_for_completion(&fcomp.comp);
102272a9730bSKrishna Gudipati 	ret = fcomp.comp_status;
102372a9730bSKrishna Gudipati done:
102472a9730bSKrishna Gudipati 	return ret;
102572a9730bSKrishna Gudipati }
102672a9730bSKrishna Gudipati 
102757b9bef0SKrishna Gudipati static int
bnad_flash_device(struct net_device * netdev,struct ethtool_flash * eflash)102857b9bef0SKrishna Gudipati bnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash)
102957b9bef0SKrishna Gudipati {
103057b9bef0SKrishna Gudipati 	struct bnad *bnad = netdev_priv(netdev);
103157b9bef0SKrishna Gudipati 	struct bnad_iocmd_comp fcomp;
103257b9bef0SKrishna Gudipati 	const struct firmware *fw;
103357b9bef0SKrishna Gudipati 	int ret = 0;
103457b9bef0SKrishna Gudipati 
103557b9bef0SKrishna Gudipati 	ret = request_firmware(&fw, eflash->data, &bnad->pcidev->dev);
103657b9bef0SKrishna Gudipati 	if (ret) {
1037ecc46789SIvan Vecera 		netdev_err(netdev, "can't load firmware %s\n", eflash->data);
103857b9bef0SKrishna Gudipati 		goto out;
103957b9bef0SKrishna Gudipati 	}
104057b9bef0SKrishna Gudipati 
104157b9bef0SKrishna Gudipati 	fcomp.bnad = bnad;
104257b9bef0SKrishna Gudipati 	fcomp.comp_status = 0;
104357b9bef0SKrishna Gudipati 
104457b9bef0SKrishna Gudipati 	init_completion(&fcomp.comp);
104557b9bef0SKrishna Gudipati 	spin_lock_irq(&bnad->bna_lock);
104657b9bef0SKrishna Gudipati 	ret = bfa_nw_flash_update_part(&bnad->bna.flash, BFA_FLASH_PART_FWIMG,
104757b9bef0SKrishna Gudipati 				bnad->id, (u8 *)fw->data, fw->size, 0,
104857b9bef0SKrishna Gudipati 				bnad_cb_completion, &fcomp);
104957b9bef0SKrishna Gudipati 	if (ret != BFA_STATUS_OK) {
1050ecc46789SIvan Vecera 		netdev_warn(netdev, "flash update failed with err=%d\n", ret);
105157b9bef0SKrishna Gudipati 		ret = -EIO;
105257b9bef0SKrishna Gudipati 		spin_unlock_irq(&bnad->bna_lock);
105357b9bef0SKrishna Gudipati 		goto out;
105457b9bef0SKrishna Gudipati 	}
105557b9bef0SKrishna Gudipati 
105657b9bef0SKrishna Gudipati 	spin_unlock_irq(&bnad->bna_lock);
105757b9bef0SKrishna Gudipati 	wait_for_completion(&fcomp.comp);
105857b9bef0SKrishna Gudipati 	if (fcomp.comp_status != BFA_STATUS_OK) {
105957b9bef0SKrishna Gudipati 		ret = -EIO;
1060ecc46789SIvan Vecera 		netdev_warn(netdev,
1061ecc46789SIvan Vecera 			    "firmware image update failed with err=%d\n",
106257b9bef0SKrishna Gudipati 			    fcomp.comp_status);
106357b9bef0SKrishna Gudipati 	}
106457b9bef0SKrishna Gudipati out:
106557b9bef0SKrishna Gudipati 	release_firmware(fw);
106657b9bef0SKrishna Gudipati 	return ret;
106757b9bef0SKrishna Gudipati }
106857b9bef0SKrishna Gudipati 
1069975419cfSstephen hemminger static const struct ethtool_ops bnad_ethtool_ops = {
1070659d0760SJakub Kicinski 	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
1071659d0760SJakub Kicinski 				     ETHTOOL_COALESCE_TX_MAX_FRAMES |
1072659d0760SJakub Kicinski 				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
10738b230ed8SRasesh Mody 	.get_drvinfo = bnad_get_drvinfo,
10748b230ed8SRasesh Mody 	.get_wol = bnad_get_wol,
10758b230ed8SRasesh Mody 	.get_link = ethtool_op_get_link,
10768b230ed8SRasesh Mody 	.get_coalesce = bnad_get_coalesce,
10778b230ed8SRasesh Mody 	.set_coalesce = bnad_set_coalesce,
10788b230ed8SRasesh Mody 	.get_ringparam = bnad_get_ringparam,
10798b230ed8SRasesh Mody 	.set_ringparam = bnad_set_ringparam,
10808b230ed8SRasesh Mody 	.get_pauseparam = bnad_get_pauseparam,
10818b230ed8SRasesh Mody 	.set_pauseparam = bnad_set_pauseparam,
10828b230ed8SRasesh Mody 	.get_strings = bnad_get_strings,
10838b230ed8SRasesh Mody 	.get_ethtool_stats = bnad_get_ethtool_stats,
108472a9730bSKrishna Gudipati 	.get_sset_count = bnad_get_sset_count,
108572a9730bSKrishna Gudipati 	.get_eeprom_len = bnad_get_eeprom_len,
108672a9730bSKrishna Gudipati 	.get_eeprom = bnad_get_eeprom,
108772a9730bSKrishna Gudipati 	.set_eeprom = bnad_set_eeprom,
108857b9bef0SKrishna Gudipati 	.flash_device = bnad_flash_device,
1089fee1253eSRasesh Mody 	.get_ts_info = ethtool_op_get_ts_info,
1090377fa64fSPhilippe Reynes 	.get_link_ksettings = bnad_get_link_ksettings,
1091377fa64fSPhilippe Reynes 	.set_link_ksettings = bnad_set_link_ksettings,
10928b230ed8SRasesh Mody };
10938b230ed8SRasesh Mody 
10948b230ed8SRasesh Mody void
bnad_set_ethtool_ops(struct net_device * netdev)10958b230ed8SRasesh Mody bnad_set_ethtool_ops(struct net_device *netdev)
10968b230ed8SRasesh Mody {
10977ad24ea4SWilfried Klaebe 	netdev->ethtool_ops = &bnad_ethtool_ops;
10988b230ed8SRasesh Mody }
1099