162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux network driver for QLogic BR-series Converged Network Adapter. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. 762306a36Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation 862306a36Sopenharmony_ci * All rights reserved 962306a36Sopenharmony_ci * www.qlogic.com 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "cna.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/netdevice.h> 1562306a36Sopenharmony_ci#include <linux/skbuff.h> 1662306a36Sopenharmony_ci#include <linux/ethtool.h> 1762306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "bna.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "bnad.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define BNAD_NUM_TXF_COUNTERS 12 2462306a36Sopenharmony_ci#define BNAD_NUM_RXF_COUNTERS 10 2562306a36Sopenharmony_ci#define BNAD_NUM_CQ_COUNTERS (3 + 5) 2662306a36Sopenharmony_ci#define BNAD_NUM_RXQ_COUNTERS 7 2762306a36Sopenharmony_ci#define BNAD_NUM_TXQ_COUNTERS 5 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic const char *bnad_net_stats_strings[] = { 3062306a36Sopenharmony_ci "rx_packets", 3162306a36Sopenharmony_ci "tx_packets", 3262306a36Sopenharmony_ci "rx_bytes", 3362306a36Sopenharmony_ci "tx_bytes", 3462306a36Sopenharmony_ci "rx_errors", 3562306a36Sopenharmony_ci "tx_errors", 3662306a36Sopenharmony_ci "rx_dropped", 3762306a36Sopenharmony_ci "tx_dropped", 3862306a36Sopenharmony_ci "multicast", 3962306a36Sopenharmony_ci "collisions", 4062306a36Sopenharmony_ci "rx_length_errors", 4162306a36Sopenharmony_ci "rx_crc_errors", 4262306a36Sopenharmony_ci "rx_frame_errors", 4362306a36Sopenharmony_ci "tx_fifo_errors", 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci "netif_queue_stop", 4662306a36Sopenharmony_ci "netif_queue_wakeup", 4762306a36Sopenharmony_ci "netif_queue_stopped", 4862306a36Sopenharmony_ci "tso4", 4962306a36Sopenharmony_ci "tso6", 5062306a36Sopenharmony_ci "tso_err", 5162306a36Sopenharmony_ci "tcpcsum_offload", 5262306a36Sopenharmony_ci "udpcsum_offload", 5362306a36Sopenharmony_ci "csum_help", 5462306a36Sopenharmony_ci "tx_skb_too_short", 5562306a36Sopenharmony_ci "tx_skb_stopping", 5662306a36Sopenharmony_ci "tx_skb_max_vectors", 5762306a36Sopenharmony_ci "tx_skb_mss_too_long", 5862306a36Sopenharmony_ci "tx_skb_tso_too_short", 5962306a36Sopenharmony_ci "tx_skb_tso_prepare", 6062306a36Sopenharmony_ci "tx_skb_non_tso_too_long", 6162306a36Sopenharmony_ci "tx_skb_tcp_hdr", 6262306a36Sopenharmony_ci "tx_skb_udp_hdr", 6362306a36Sopenharmony_ci "tx_skb_csum_err", 6462306a36Sopenharmony_ci "tx_skb_headlen_too_long", 6562306a36Sopenharmony_ci "tx_skb_headlen_zero", 6662306a36Sopenharmony_ci "tx_skb_frag_zero", 6762306a36Sopenharmony_ci "tx_skb_len_mismatch", 6862306a36Sopenharmony_ci "tx_skb_map_failed", 6962306a36Sopenharmony_ci "hw_stats_updates", 7062306a36Sopenharmony_ci "netif_rx_dropped", 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci "link_toggle", 7362306a36Sopenharmony_ci "cee_toggle", 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci "rxp_info_alloc_failed", 7662306a36Sopenharmony_ci "mbox_intr_disabled", 7762306a36Sopenharmony_ci "mbox_intr_enabled", 7862306a36Sopenharmony_ci "tx_unmap_q_alloc_failed", 7962306a36Sopenharmony_ci "rx_unmap_q_alloc_failed", 8062306a36Sopenharmony_ci "rxbuf_alloc_failed", 8162306a36Sopenharmony_ci "rxbuf_map_failed", 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci "mac_stats_clr_cnt", 8462306a36Sopenharmony_ci "mac_frame_64", 8562306a36Sopenharmony_ci "mac_frame_65_127", 8662306a36Sopenharmony_ci "mac_frame_128_255", 8762306a36Sopenharmony_ci "mac_frame_256_511", 8862306a36Sopenharmony_ci "mac_frame_512_1023", 8962306a36Sopenharmony_ci "mac_frame_1024_1518", 9062306a36Sopenharmony_ci "mac_frame_1518_1522", 9162306a36Sopenharmony_ci "mac_rx_bytes", 9262306a36Sopenharmony_ci "mac_rx_packets", 9362306a36Sopenharmony_ci "mac_rx_fcs_error", 9462306a36Sopenharmony_ci "mac_rx_multicast", 9562306a36Sopenharmony_ci "mac_rx_broadcast", 9662306a36Sopenharmony_ci "mac_rx_control_frames", 9762306a36Sopenharmony_ci "mac_rx_pause", 9862306a36Sopenharmony_ci "mac_rx_unknown_opcode", 9962306a36Sopenharmony_ci "mac_rx_alignment_error", 10062306a36Sopenharmony_ci "mac_rx_frame_length_error", 10162306a36Sopenharmony_ci "mac_rx_code_error", 10262306a36Sopenharmony_ci "mac_rx_carrier_sense_error", 10362306a36Sopenharmony_ci "mac_rx_undersize", 10462306a36Sopenharmony_ci "mac_rx_oversize", 10562306a36Sopenharmony_ci "mac_rx_fragments", 10662306a36Sopenharmony_ci "mac_rx_jabber", 10762306a36Sopenharmony_ci "mac_rx_drop", 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci "mac_tx_bytes", 11062306a36Sopenharmony_ci "mac_tx_packets", 11162306a36Sopenharmony_ci "mac_tx_multicast", 11262306a36Sopenharmony_ci "mac_tx_broadcast", 11362306a36Sopenharmony_ci "mac_tx_pause", 11462306a36Sopenharmony_ci "mac_tx_deferral", 11562306a36Sopenharmony_ci "mac_tx_excessive_deferral", 11662306a36Sopenharmony_ci "mac_tx_single_collision", 11762306a36Sopenharmony_ci "mac_tx_multiple_collision", 11862306a36Sopenharmony_ci "mac_tx_late_collision", 11962306a36Sopenharmony_ci "mac_tx_excessive_collision", 12062306a36Sopenharmony_ci "mac_tx_total_collision", 12162306a36Sopenharmony_ci "mac_tx_pause_honored", 12262306a36Sopenharmony_ci "mac_tx_drop", 12362306a36Sopenharmony_ci "mac_tx_jabber", 12462306a36Sopenharmony_ci "mac_tx_fcs_error", 12562306a36Sopenharmony_ci "mac_tx_control_frame", 12662306a36Sopenharmony_ci "mac_tx_oversize", 12762306a36Sopenharmony_ci "mac_tx_undersize", 12862306a36Sopenharmony_ci "mac_tx_fragments", 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci "bpc_tx_pause_0", 13162306a36Sopenharmony_ci "bpc_tx_pause_1", 13262306a36Sopenharmony_ci "bpc_tx_pause_2", 13362306a36Sopenharmony_ci "bpc_tx_pause_3", 13462306a36Sopenharmony_ci "bpc_tx_pause_4", 13562306a36Sopenharmony_ci "bpc_tx_pause_5", 13662306a36Sopenharmony_ci "bpc_tx_pause_6", 13762306a36Sopenharmony_ci "bpc_tx_pause_7", 13862306a36Sopenharmony_ci "bpc_tx_zero_pause_0", 13962306a36Sopenharmony_ci "bpc_tx_zero_pause_1", 14062306a36Sopenharmony_ci "bpc_tx_zero_pause_2", 14162306a36Sopenharmony_ci "bpc_tx_zero_pause_3", 14262306a36Sopenharmony_ci "bpc_tx_zero_pause_4", 14362306a36Sopenharmony_ci "bpc_tx_zero_pause_5", 14462306a36Sopenharmony_ci "bpc_tx_zero_pause_6", 14562306a36Sopenharmony_ci "bpc_tx_zero_pause_7", 14662306a36Sopenharmony_ci "bpc_tx_first_pause_0", 14762306a36Sopenharmony_ci "bpc_tx_first_pause_1", 14862306a36Sopenharmony_ci "bpc_tx_first_pause_2", 14962306a36Sopenharmony_ci "bpc_tx_first_pause_3", 15062306a36Sopenharmony_ci "bpc_tx_first_pause_4", 15162306a36Sopenharmony_ci "bpc_tx_first_pause_5", 15262306a36Sopenharmony_ci "bpc_tx_first_pause_6", 15362306a36Sopenharmony_ci "bpc_tx_first_pause_7", 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci "bpc_rx_pause_0", 15662306a36Sopenharmony_ci "bpc_rx_pause_1", 15762306a36Sopenharmony_ci "bpc_rx_pause_2", 15862306a36Sopenharmony_ci "bpc_rx_pause_3", 15962306a36Sopenharmony_ci "bpc_rx_pause_4", 16062306a36Sopenharmony_ci "bpc_rx_pause_5", 16162306a36Sopenharmony_ci "bpc_rx_pause_6", 16262306a36Sopenharmony_ci "bpc_rx_pause_7", 16362306a36Sopenharmony_ci "bpc_rx_zero_pause_0", 16462306a36Sopenharmony_ci "bpc_rx_zero_pause_1", 16562306a36Sopenharmony_ci "bpc_rx_zero_pause_2", 16662306a36Sopenharmony_ci "bpc_rx_zero_pause_3", 16762306a36Sopenharmony_ci "bpc_rx_zero_pause_4", 16862306a36Sopenharmony_ci "bpc_rx_zero_pause_5", 16962306a36Sopenharmony_ci "bpc_rx_zero_pause_6", 17062306a36Sopenharmony_ci "bpc_rx_zero_pause_7", 17162306a36Sopenharmony_ci "bpc_rx_first_pause_0", 17262306a36Sopenharmony_ci "bpc_rx_first_pause_1", 17362306a36Sopenharmony_ci "bpc_rx_first_pause_2", 17462306a36Sopenharmony_ci "bpc_rx_first_pause_3", 17562306a36Sopenharmony_ci "bpc_rx_first_pause_4", 17662306a36Sopenharmony_ci "bpc_rx_first_pause_5", 17762306a36Sopenharmony_ci "bpc_rx_first_pause_6", 17862306a36Sopenharmony_ci "bpc_rx_first_pause_7", 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci "rad_rx_frames", 18162306a36Sopenharmony_ci "rad_rx_octets", 18262306a36Sopenharmony_ci "rad_rx_vlan_frames", 18362306a36Sopenharmony_ci "rad_rx_ucast", 18462306a36Sopenharmony_ci "rad_rx_ucast_octets", 18562306a36Sopenharmony_ci "rad_rx_ucast_vlan", 18662306a36Sopenharmony_ci "rad_rx_mcast", 18762306a36Sopenharmony_ci "rad_rx_mcast_octets", 18862306a36Sopenharmony_ci "rad_rx_mcast_vlan", 18962306a36Sopenharmony_ci "rad_rx_bcast", 19062306a36Sopenharmony_ci "rad_rx_bcast_octets", 19162306a36Sopenharmony_ci "rad_rx_bcast_vlan", 19262306a36Sopenharmony_ci "rad_rx_drops", 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci "rlb_rad_rx_frames", 19562306a36Sopenharmony_ci "rlb_rad_rx_octets", 19662306a36Sopenharmony_ci "rlb_rad_rx_vlan_frames", 19762306a36Sopenharmony_ci "rlb_rad_rx_ucast", 19862306a36Sopenharmony_ci "rlb_rad_rx_ucast_octets", 19962306a36Sopenharmony_ci "rlb_rad_rx_ucast_vlan", 20062306a36Sopenharmony_ci "rlb_rad_rx_mcast", 20162306a36Sopenharmony_ci "rlb_rad_rx_mcast_octets", 20262306a36Sopenharmony_ci "rlb_rad_rx_mcast_vlan", 20362306a36Sopenharmony_ci "rlb_rad_rx_bcast", 20462306a36Sopenharmony_ci "rlb_rad_rx_bcast_octets", 20562306a36Sopenharmony_ci "rlb_rad_rx_bcast_vlan", 20662306a36Sopenharmony_ci "rlb_rad_rx_drops", 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci "fc_rx_ucast_octets", 20962306a36Sopenharmony_ci "fc_rx_ucast", 21062306a36Sopenharmony_ci "fc_rx_ucast_vlan", 21162306a36Sopenharmony_ci "fc_rx_mcast_octets", 21262306a36Sopenharmony_ci "fc_rx_mcast", 21362306a36Sopenharmony_ci "fc_rx_mcast_vlan", 21462306a36Sopenharmony_ci "fc_rx_bcast_octets", 21562306a36Sopenharmony_ci "fc_rx_bcast", 21662306a36Sopenharmony_ci "fc_rx_bcast_vlan", 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci "fc_tx_ucast_octets", 21962306a36Sopenharmony_ci "fc_tx_ucast", 22062306a36Sopenharmony_ci "fc_tx_ucast_vlan", 22162306a36Sopenharmony_ci "fc_tx_mcast_octets", 22262306a36Sopenharmony_ci "fc_tx_mcast", 22362306a36Sopenharmony_ci "fc_tx_mcast_vlan", 22462306a36Sopenharmony_ci "fc_tx_bcast_octets", 22562306a36Sopenharmony_ci "fc_tx_bcast", 22662306a36Sopenharmony_ci "fc_tx_bcast_vlan", 22762306a36Sopenharmony_ci "fc_tx_parity_errors", 22862306a36Sopenharmony_ci "fc_tx_timeout", 22962306a36Sopenharmony_ci "fc_tx_fid_parity_errors", 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#define BNAD_ETHTOOL_STATS_NUM ARRAY_SIZE(bnad_net_stats_strings) 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int 23562306a36Sopenharmony_cibnad_get_link_ksettings(struct net_device *netdev, 23662306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 23962306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseCR_Full); 24262306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseSR_Full); 24362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseLR_Full); 24462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseCR_Full); 24562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseSR_Full); 24662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseLR_Full); 24762306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 24862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 24962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); 25062306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 25162306a36Sopenharmony_ci cmd->base.phy_address = 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (netif_carrier_ok(netdev)) { 25462306a36Sopenharmony_ci cmd->base.speed = SPEED_10000; 25562306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 25862306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int 26562306a36Sopenharmony_cibnad_set_link_ksettings(struct net_device *netdev, 26662306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci /* 10G full duplex setting supported only */ 26962306a36Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_ENABLE) 27062306a36Sopenharmony_ci return -EOPNOTSUPP; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if ((cmd->base.speed == SPEED_10000) && 27362306a36Sopenharmony_ci (cmd->base.duplex == DUPLEX_FULL)) 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return -EOPNOTSUPP; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void 28062306a36Sopenharmony_cibnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 28362306a36Sopenharmony_ci struct bfa_ioc_attr *ioc_attr; 28462306a36Sopenharmony_ci unsigned long flags; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci strscpy(drvinfo->driver, BNAD_NAME, sizeof(drvinfo->driver)); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL); 28962306a36Sopenharmony_ci if (ioc_attr) { 29062306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 29162306a36Sopenharmony_ci bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr); 29262306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci strscpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver, 29562306a36Sopenharmony_ci sizeof(drvinfo->fw_version)); 29662306a36Sopenharmony_ci kfree(ioc_attr); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci strscpy(drvinfo->bus_info, pci_name(bnad->pcidev), 30062306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void 30462306a36Sopenharmony_cibnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci wolinfo->supported = 0; 30762306a36Sopenharmony_ci wolinfo->wolopts = 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int bnad_get_coalesce(struct net_device *netdev, 31162306a36Sopenharmony_ci struct ethtool_coalesce *coalesce, 31262306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 31362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 31662306a36Sopenharmony_ci unsigned long flags; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Lock rqd. to access bnad->bna_lock */ 31962306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 32062306a36Sopenharmony_ci coalesce->use_adaptive_rx_coalesce = 32162306a36Sopenharmony_ci (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) ? true : false; 32262306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo * 32562306a36Sopenharmony_ci BFI_COALESCING_TIMER_UNIT; 32662306a36Sopenharmony_ci coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo * 32762306a36Sopenharmony_ci BFI_COALESCING_TIMER_UNIT; 32862306a36Sopenharmony_ci coalesce->tx_max_coalesced_frames = BFI_TX_INTERPKT_COUNT; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int bnad_set_coalesce(struct net_device *netdev, 33462306a36Sopenharmony_ci struct ethtool_coalesce *coalesce, 33562306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 33662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 33962306a36Sopenharmony_ci unsigned long flags; 34062306a36Sopenharmony_ci int to_del = 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (coalesce->rx_coalesce_usecs == 0 || 34362306a36Sopenharmony_ci coalesce->rx_coalesce_usecs > 34462306a36Sopenharmony_ci BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT) 34562306a36Sopenharmony_ci return -EINVAL; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (coalesce->tx_coalesce_usecs == 0 || 34862306a36Sopenharmony_ci coalesce->tx_coalesce_usecs > 34962306a36Sopenharmony_ci BFI_MAX_COALESCING_TIMEO * BFI_COALESCING_TIMER_UNIT) 35062306a36Sopenharmony_ci return -EINVAL; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 35362306a36Sopenharmony_ci /* 35462306a36Sopenharmony_ci * Do not need to store rx_coalesce_usecs here 35562306a36Sopenharmony_ci * Every time DIM is disabled, we can get it from the 35662306a36Sopenharmony_ci * stack. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 35962306a36Sopenharmony_ci if (coalesce->use_adaptive_rx_coalesce) { 36062306a36Sopenharmony_ci if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) { 36162306a36Sopenharmony_ci bnad->cfg_flags |= BNAD_CF_DIM_ENABLED; 36262306a36Sopenharmony_ci bnad_dim_timer_start(bnad); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) { 36662306a36Sopenharmony_ci bnad->cfg_flags &= ~BNAD_CF_DIM_ENABLED; 36762306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED && 36862306a36Sopenharmony_ci test_bit(BNAD_RF_DIM_TIMER_RUNNING, 36962306a36Sopenharmony_ci &bnad->run_flags)) { 37062306a36Sopenharmony_ci clear_bit(BNAD_RF_DIM_TIMER_RUNNING, 37162306a36Sopenharmony_ci &bnad->run_flags); 37262306a36Sopenharmony_ci to_del = 1; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 37562306a36Sopenharmony_ci if (to_del) 37662306a36Sopenharmony_ci del_timer_sync(&bnad->dim_timer); 37762306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 37862306a36Sopenharmony_ci bnad_rx_coalescing_timeo_set(bnad); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci if (bnad->tx_coalescing_timeo != coalesce->tx_coalesce_usecs / 38262306a36Sopenharmony_ci BFI_COALESCING_TIMER_UNIT) { 38362306a36Sopenharmony_ci bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs / 38462306a36Sopenharmony_ci BFI_COALESCING_TIMER_UNIT; 38562306a36Sopenharmony_ci bnad_tx_coalescing_timeo_set(bnad); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (bnad->rx_coalescing_timeo != coalesce->rx_coalesce_usecs / 38962306a36Sopenharmony_ci BFI_COALESCING_TIMER_UNIT) { 39062306a36Sopenharmony_ci bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs / 39162306a36Sopenharmony_ci BFI_COALESCING_TIMER_UNIT; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!(bnad->cfg_flags & BNAD_CF_DIM_ENABLED)) 39462306a36Sopenharmony_ci bnad_rx_coalescing_timeo_set(bnad); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Add Tx Inter-pkt DMA count? */ 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void 40762306a36Sopenharmony_cibnad_get_ringparam(struct net_device *netdev, 40862306a36Sopenharmony_ci struct ethtool_ringparam *ringparam, 40962306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ringparam, 41062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ringparam->rx_max_pending = BNAD_MAX_RXQ_DEPTH; 41562306a36Sopenharmony_ci ringparam->tx_max_pending = BNAD_MAX_TXQ_DEPTH; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci ringparam->rx_pending = bnad->rxq_depth; 41862306a36Sopenharmony_ci ringparam->tx_pending = bnad->txq_depth; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int 42262306a36Sopenharmony_cibnad_set_ringparam(struct net_device *netdev, 42362306a36Sopenharmony_ci struct ethtool_ringparam *ringparam, 42462306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ringparam, 42562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci int i, current_err, err = 0; 42862306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 42962306a36Sopenharmony_ci unsigned long flags; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 43262306a36Sopenharmony_ci if (ringparam->rx_pending == bnad->rxq_depth && 43362306a36Sopenharmony_ci ringparam->tx_pending == bnad->txq_depth) { 43462306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 43562306a36Sopenharmony_ci return 0; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH || 43962306a36Sopenharmony_ci ringparam->rx_pending > BNAD_MAX_RXQ_DEPTH || 44062306a36Sopenharmony_ci !is_power_of_2(ringparam->rx_pending)) { 44162306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH || 44562306a36Sopenharmony_ci ringparam->tx_pending > BNAD_MAX_TXQ_DEPTH || 44662306a36Sopenharmony_ci !is_power_of_2(ringparam->tx_pending)) { 44762306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 44862306a36Sopenharmony_ci return -EINVAL; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (ringparam->rx_pending != bnad->rxq_depth) { 45262306a36Sopenharmony_ci bnad->rxq_depth = ringparam->rx_pending; 45362306a36Sopenharmony_ci if (!netif_running(netdev)) { 45462306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 45962306a36Sopenharmony_ci if (!bnad->rx_info[i].rx) 46062306a36Sopenharmony_ci continue; 46162306a36Sopenharmony_ci bnad_destroy_rx(bnad, i); 46262306a36Sopenharmony_ci current_err = bnad_setup_rx(bnad, i); 46362306a36Sopenharmony_ci if (current_err && !err) 46462306a36Sopenharmony_ci err = current_err; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!err && bnad->rx_info[0].rx) { 46862306a36Sopenharmony_ci /* restore rx configuration */ 46962306a36Sopenharmony_ci bnad_restore_vlans(bnad, 0); 47062306a36Sopenharmony_ci bnad_enable_default_bcast(bnad); 47162306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 47262306a36Sopenharmony_ci bnad_mac_addr_set_locked(bnad, netdev->dev_addr); 47362306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 47462306a36Sopenharmony_ci bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI | 47562306a36Sopenharmony_ci BNAD_CF_PROMISC); 47662306a36Sopenharmony_ci bnad_set_rx_mode(netdev); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci if (ringparam->tx_pending != bnad->txq_depth) { 48062306a36Sopenharmony_ci bnad->txq_depth = ringparam->tx_pending; 48162306a36Sopenharmony_ci if (!netif_running(netdev)) { 48262306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci for (i = 0; i < bnad->num_tx; i++) { 48762306a36Sopenharmony_ci if (!bnad->tx_info[i].tx) 48862306a36Sopenharmony_ci continue; 48962306a36Sopenharmony_ci bnad_destroy_tx(bnad, i); 49062306a36Sopenharmony_ci current_err = bnad_setup_tx(bnad, i); 49162306a36Sopenharmony_ci if (current_err && !err) 49262306a36Sopenharmony_ci err = current_err; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 49762306a36Sopenharmony_ci return err; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void 50162306a36Sopenharmony_cibnad_get_pauseparam(struct net_device *netdev, 50262306a36Sopenharmony_ci struct ethtool_pauseparam *pauseparam) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci pauseparam->autoneg = 0; 50762306a36Sopenharmony_ci pauseparam->rx_pause = bnad->bna.enet.pause_config.rx_pause; 50862306a36Sopenharmony_ci pauseparam->tx_pause = bnad->bna.enet.pause_config.tx_pause; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int 51262306a36Sopenharmony_cibnad_set_pauseparam(struct net_device *netdev, 51362306a36Sopenharmony_ci struct ethtool_pauseparam *pauseparam) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 51662306a36Sopenharmony_ci struct bna_pause_config pause_config; 51762306a36Sopenharmony_ci unsigned long flags; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (pauseparam->autoneg == AUTONEG_ENABLE) 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 52362306a36Sopenharmony_ci if (pauseparam->rx_pause != bnad->bna.enet.pause_config.rx_pause || 52462306a36Sopenharmony_ci pauseparam->tx_pause != bnad->bna.enet.pause_config.tx_pause) { 52562306a36Sopenharmony_ci pause_config.rx_pause = pauseparam->rx_pause; 52662306a36Sopenharmony_ci pause_config.tx_pause = pauseparam->tx_pause; 52762306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 52862306a36Sopenharmony_ci bna_enet_pause_config(&bnad->bna.enet, &pause_config); 52962306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void bnad_get_txf_strings(u8 **string, int f_num) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_ucast_octets", f_num); 53862306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_ucast", f_num); 53962306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_ucast_vlan", f_num); 54062306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_mcast_octets", f_num); 54162306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_mcast", f_num); 54262306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_mcast_vlan", f_num); 54362306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_bcast_octets", f_num); 54462306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_bcast", f_num); 54562306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_bcast_vlan", f_num); 54662306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_errors", f_num); 54762306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_filter_vlan", f_num); 54862306a36Sopenharmony_ci ethtool_sprintf(string, "txf%d_filter_mac_sa", f_num); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void bnad_get_rxf_strings(u8 **string, int f_num) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_ucast_octets", f_num); 55462306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_ucast", f_num); 55562306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_ucast_vlan", f_num); 55662306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_mcast_octets", f_num); 55762306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_mcast", f_num); 55862306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_mcast_vlan", f_num); 55962306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_bcast_octets", f_num); 56062306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_bcast", f_num); 56162306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_bcast_vlan", f_num); 56262306a36Sopenharmony_ci ethtool_sprintf(string, "rxf%d_frame_drops", f_num); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic void bnad_get_cq_strings(u8 **string, int q_num) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_producer_index", q_num); 56862306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_consumer_index", q_num); 56962306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_hw_producer_index", q_num); 57062306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_intr", q_num); 57162306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_poll", q_num); 57262306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_schedule", q_num); 57362306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_keep_poll", q_num); 57462306a36Sopenharmony_ci ethtool_sprintf(string, "cq%d_complete", q_num); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic void bnad_get_rxq_strings(u8 **string, int q_num) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_packets", q_num); 58062306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_bytes", q_num); 58162306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_packets_with_error", q_num); 58262306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_allocbuf_failed", q_num); 58362306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_mapbuf_failed", q_num); 58462306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_producer_index", q_num); 58562306a36Sopenharmony_ci ethtool_sprintf(string, "rxq%d_consumer_index", q_num); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic void bnad_get_txq_strings(u8 **string, int q_num) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci ethtool_sprintf(string, "txq%d_packets", q_num); 59162306a36Sopenharmony_ci ethtool_sprintf(string, "txq%d_bytes", q_num); 59262306a36Sopenharmony_ci ethtool_sprintf(string, "txq%d_producer_index", q_num); 59362306a36Sopenharmony_ci ethtool_sprintf(string, "txq%d_consumer_index", q_num); 59462306a36Sopenharmony_ci ethtool_sprintf(string, "txq%d_hw_consumer_index", q_num); 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void 59862306a36Sopenharmony_cibnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 60162306a36Sopenharmony_ci int i, j, q_num; 60262306a36Sopenharmony_ci u32 bmap; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (stringset != ETH_SS_STATS) 60562306a36Sopenharmony_ci return; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) { 61062306a36Sopenharmony_ci BUG_ON(!(strlen(bnad_net_stats_strings[i]) < ETH_GSTRING_LEN)); 61162306a36Sopenharmony_ci ethtool_sprintf(&string, bnad_net_stats_strings[i]); 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci bmap = bna_tx_rid_mask(&bnad->bna); 61562306a36Sopenharmony_ci for (i = 0; bmap; i++) { 61662306a36Sopenharmony_ci if (bmap & 1) 61762306a36Sopenharmony_ci bnad_get_txf_strings(&string, i); 61862306a36Sopenharmony_ci bmap >>= 1; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci bmap = bna_rx_rid_mask(&bnad->bna); 62262306a36Sopenharmony_ci for (i = 0; bmap; i++, bmap >>= 1) { 62362306a36Sopenharmony_ci if (bmap & 1) 62462306a36Sopenharmony_ci bnad_get_rxf_strings(&string, i); 62562306a36Sopenharmony_ci bmap >>= 1; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci q_num = 0; 62962306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 63062306a36Sopenharmony_ci if (!bnad->rx_info[i].rx) 63162306a36Sopenharmony_ci continue; 63262306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) 63362306a36Sopenharmony_ci bnad_get_cq_strings(&string, q_num++); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci q_num = 0; 63762306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 63862306a36Sopenharmony_ci if (!bnad->rx_info[i].rx) 63962306a36Sopenharmony_ci continue; 64062306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) { 64162306a36Sopenharmony_ci bnad_get_rxq_strings(&string, q_num++); 64262306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb && 64362306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] && 64462306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq) 64562306a36Sopenharmony_ci bnad_get_rxq_strings(&string, q_num++); 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci q_num = 0; 65062306a36Sopenharmony_ci for (i = 0; i < bnad->num_tx; i++) { 65162306a36Sopenharmony_ci if (!bnad->tx_info[i].tx) 65262306a36Sopenharmony_ci continue; 65362306a36Sopenharmony_ci for (j = 0; j < bnad->num_txq_per_tx; j++) 65462306a36Sopenharmony_ci bnad_get_txq_strings(&string, q_num++); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int 66162306a36Sopenharmony_cibnad_get_stats_count_locked(struct net_device *netdev) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 66462306a36Sopenharmony_ci int i, j, count = 0, rxf_active_num = 0, txf_active_num = 0; 66562306a36Sopenharmony_ci u32 bmap; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci bmap = bna_tx_rid_mask(&bnad->bna); 66862306a36Sopenharmony_ci for (i = 0; bmap; i++) { 66962306a36Sopenharmony_ci if (bmap & 1) 67062306a36Sopenharmony_ci txf_active_num++; 67162306a36Sopenharmony_ci bmap >>= 1; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci bmap = bna_rx_rid_mask(&bnad->bna); 67462306a36Sopenharmony_ci for (i = 0; bmap; i++) { 67562306a36Sopenharmony_ci if (bmap & 1) 67662306a36Sopenharmony_ci rxf_active_num++; 67762306a36Sopenharmony_ci bmap >>= 1; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci count = BNAD_ETHTOOL_STATS_NUM + 68062306a36Sopenharmony_ci txf_active_num * BNAD_NUM_TXF_COUNTERS + 68162306a36Sopenharmony_ci rxf_active_num * BNAD_NUM_RXF_COUNTERS; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 68462306a36Sopenharmony_ci if (!bnad->rx_info[i].rx) 68562306a36Sopenharmony_ci continue; 68662306a36Sopenharmony_ci count += bnad->num_rxp_per_rx * BNAD_NUM_CQ_COUNTERS; 68762306a36Sopenharmony_ci count += bnad->num_rxp_per_rx * BNAD_NUM_RXQ_COUNTERS; 68862306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) 68962306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb && 69062306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] && 69162306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1]->rxq) 69262306a36Sopenharmony_ci count += BNAD_NUM_RXQ_COUNTERS; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci for (i = 0; i < bnad->num_tx; i++) { 69662306a36Sopenharmony_ci if (!bnad->tx_info[i].tx) 69762306a36Sopenharmony_ci continue; 69862306a36Sopenharmony_ci count += bnad->num_txq_per_tx * BNAD_NUM_TXQ_COUNTERS; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci return count; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int 70462306a36Sopenharmony_cibnad_per_q_stats_fill(struct bnad *bnad, u64 *buf, int bi) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci int i, j; 70762306a36Sopenharmony_ci struct bna_rcb *rcb = NULL; 70862306a36Sopenharmony_ci struct bna_tcb *tcb = NULL; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 71162306a36Sopenharmony_ci if (!bnad->rx_info[i].rx) 71262306a36Sopenharmony_ci continue; 71362306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) 71462306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb && 71562306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] && 71662306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0]->rxq) { 71762306a36Sopenharmony_ci buf[bi++] = bnad->rx_info[i].rx_ctrl[j]. 71862306a36Sopenharmony_ci ccb->producer_index; 71962306a36Sopenharmony_ci buf[bi++] = 0; /* ccb->consumer_index */ 72062306a36Sopenharmony_ci buf[bi++] = *(bnad->rx_info[i].rx_ctrl[j]. 72162306a36Sopenharmony_ci ccb->hw_producer_index); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci buf[bi++] = bnad->rx_info[i]. 72462306a36Sopenharmony_ci rx_ctrl[j].rx_intr_ctr; 72562306a36Sopenharmony_ci buf[bi++] = bnad->rx_info[i]. 72662306a36Sopenharmony_ci rx_ctrl[j].rx_poll_ctr; 72762306a36Sopenharmony_ci buf[bi++] = bnad->rx_info[i]. 72862306a36Sopenharmony_ci rx_ctrl[j].rx_schedule; 72962306a36Sopenharmony_ci buf[bi++] = bnad->rx_info[i]. 73062306a36Sopenharmony_ci rx_ctrl[j].rx_keep_poll; 73162306a36Sopenharmony_ci buf[bi++] = bnad->rx_info[i]. 73262306a36Sopenharmony_ci rx_ctrl[j].rx_complete; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 73662306a36Sopenharmony_ci if (!bnad->rx_info[i].rx) 73762306a36Sopenharmony_ci continue; 73862306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) 73962306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb) { 74062306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[0] && 74162306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb-> 74262306a36Sopenharmony_ci rcb[0]->rxq) { 74362306a36Sopenharmony_ci rcb = bnad->rx_info[i].rx_ctrl[j]. 74462306a36Sopenharmony_ci ccb->rcb[0]; 74562306a36Sopenharmony_ci buf[bi++] = rcb->rxq->rx_packets; 74662306a36Sopenharmony_ci buf[bi++] = rcb->rxq->rx_bytes; 74762306a36Sopenharmony_ci buf[bi++] = rcb->rxq-> 74862306a36Sopenharmony_ci rx_packets_with_error; 74962306a36Sopenharmony_ci buf[bi++] = rcb->rxq-> 75062306a36Sopenharmony_ci rxbuf_alloc_failed; 75162306a36Sopenharmony_ci buf[bi++] = rcb->rxq->rxbuf_map_failed; 75262306a36Sopenharmony_ci buf[bi++] = rcb->producer_index; 75362306a36Sopenharmony_ci buf[bi++] = rcb->consumer_index; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] && 75662306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb-> 75762306a36Sopenharmony_ci rcb[1]->rxq) { 75862306a36Sopenharmony_ci rcb = bnad->rx_info[i].rx_ctrl[j]. 75962306a36Sopenharmony_ci ccb->rcb[1]; 76062306a36Sopenharmony_ci buf[bi++] = rcb->rxq->rx_packets; 76162306a36Sopenharmony_ci buf[bi++] = rcb->rxq->rx_bytes; 76262306a36Sopenharmony_ci buf[bi++] = rcb->rxq-> 76362306a36Sopenharmony_ci rx_packets_with_error; 76462306a36Sopenharmony_ci buf[bi++] = rcb->rxq-> 76562306a36Sopenharmony_ci rxbuf_alloc_failed; 76662306a36Sopenharmony_ci buf[bi++] = rcb->rxq->rxbuf_map_failed; 76762306a36Sopenharmony_ci buf[bi++] = rcb->producer_index; 76862306a36Sopenharmony_ci buf[bi++] = rcb->consumer_index; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci for (i = 0; i < bnad->num_tx; i++) { 77462306a36Sopenharmony_ci if (!bnad->tx_info[i].tx) 77562306a36Sopenharmony_ci continue; 77662306a36Sopenharmony_ci for (j = 0; j < bnad->num_txq_per_tx; j++) 77762306a36Sopenharmony_ci if (bnad->tx_info[i].tcb[j] && 77862306a36Sopenharmony_ci bnad->tx_info[i].tcb[j]->txq) { 77962306a36Sopenharmony_ci tcb = bnad->tx_info[i].tcb[j]; 78062306a36Sopenharmony_ci buf[bi++] = tcb->txq->tx_packets; 78162306a36Sopenharmony_ci buf[bi++] = tcb->txq->tx_bytes; 78262306a36Sopenharmony_ci buf[bi++] = tcb->producer_index; 78362306a36Sopenharmony_ci buf[bi++] = tcb->consumer_index; 78462306a36Sopenharmony_ci buf[bi++] = *(tcb->hw_consumer_index); 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci return bi; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic void 79262306a36Sopenharmony_cibnad_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, 79362306a36Sopenharmony_ci u64 *buf) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 79662306a36Sopenharmony_ci int i, j, bi = 0; 79762306a36Sopenharmony_ci unsigned long flags; 79862306a36Sopenharmony_ci struct rtnl_link_stats64 net_stats64; 79962306a36Sopenharmony_ci u64 *stats64; 80062306a36Sopenharmony_ci u32 bmap; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 80362306a36Sopenharmony_ci if (bnad_get_stats_count_locked(netdev) != stats->n_stats) { 80462306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 80562306a36Sopenharmony_ci return; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * Used bna_lock to sync reads from bna_stats, which is written 81062306a36Sopenharmony_ci * under the same lock 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci memset(&net_stats64, 0, sizeof(net_stats64)); 81562306a36Sopenharmony_ci bnad_netdev_qstats_fill(bnad, &net_stats64); 81662306a36Sopenharmony_ci bnad_netdev_hwstats_fill(bnad, &net_stats64); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_packets; 81962306a36Sopenharmony_ci buf[bi++] = net_stats64.tx_packets; 82062306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_bytes; 82162306a36Sopenharmony_ci buf[bi++] = net_stats64.tx_bytes; 82262306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_errors; 82362306a36Sopenharmony_ci buf[bi++] = net_stats64.tx_errors; 82462306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_dropped; 82562306a36Sopenharmony_ci buf[bi++] = net_stats64.tx_dropped; 82662306a36Sopenharmony_ci buf[bi++] = net_stats64.multicast; 82762306a36Sopenharmony_ci buf[bi++] = net_stats64.collisions; 82862306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_length_errors; 82962306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_crc_errors; 83062306a36Sopenharmony_ci buf[bi++] = net_stats64.rx_frame_errors; 83162306a36Sopenharmony_ci buf[bi++] = net_stats64.tx_fifo_errors; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Get netif_queue_stopped from stack */ 83462306a36Sopenharmony_ci bnad->stats.drv_stats.netif_queue_stopped = netif_queue_stopped(netdev); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Fill driver stats into ethtool buffers */ 83762306a36Sopenharmony_ci stats64 = (u64 *)&bnad->stats.drv_stats; 83862306a36Sopenharmony_ci for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64); i++) 83962306a36Sopenharmony_ci buf[bi++] = stats64[i]; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* Fill hardware stats excluding the rxf/txf into ethtool bufs */ 84262306a36Sopenharmony_ci stats64 = (u64 *) &bnad->stats.bna_stats->hw_stats; 84362306a36Sopenharmony_ci for (i = 0; 84462306a36Sopenharmony_ci i < offsetof(struct bfi_enet_stats, rxf_stats[0]) / 84562306a36Sopenharmony_ci sizeof(u64); 84662306a36Sopenharmony_ci i++) 84762306a36Sopenharmony_ci buf[bi++] = stats64[i]; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* Fill txf stats into ethtool buffers */ 85062306a36Sopenharmony_ci bmap = bna_tx_rid_mask(&bnad->bna); 85162306a36Sopenharmony_ci for (i = 0; bmap; i++) { 85262306a36Sopenharmony_ci if (bmap & 1) { 85362306a36Sopenharmony_ci stats64 = (u64 *)&bnad->stats.bna_stats-> 85462306a36Sopenharmony_ci hw_stats.txf_stats[i]; 85562306a36Sopenharmony_ci for (j = 0; j < sizeof(struct bfi_enet_stats_txf) / 85662306a36Sopenharmony_ci sizeof(u64); j++) 85762306a36Sopenharmony_ci buf[bi++] = stats64[j]; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci bmap >>= 1; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* Fill rxf stats into ethtool buffers */ 86362306a36Sopenharmony_ci bmap = bna_rx_rid_mask(&bnad->bna); 86462306a36Sopenharmony_ci for (i = 0; bmap; i++) { 86562306a36Sopenharmony_ci if (bmap & 1) { 86662306a36Sopenharmony_ci stats64 = (u64 *)&bnad->stats.bna_stats-> 86762306a36Sopenharmony_ci hw_stats.rxf_stats[i]; 86862306a36Sopenharmony_ci for (j = 0; j < sizeof(struct bfi_enet_stats_rxf) / 86962306a36Sopenharmony_ci sizeof(u64); j++) 87062306a36Sopenharmony_ci buf[bi++] = stats64[j]; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci bmap >>= 1; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Fill per Q stats into ethtool buffers */ 87662306a36Sopenharmony_ci bi = bnad_per_q_stats_fill(bnad, buf, bi); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic int 88462306a36Sopenharmony_cibnad_get_sset_count(struct net_device *netdev, int sset) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci switch (sset) { 88762306a36Sopenharmony_ci case ETH_SS_STATS: 88862306a36Sopenharmony_ci return bnad_get_stats_count_locked(netdev); 88962306a36Sopenharmony_ci default: 89062306a36Sopenharmony_ci return -EOPNOTSUPP; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic u32 89562306a36Sopenharmony_cibnad_get_flash_partition_by_offset(struct bnad *bnad, u32 offset, 89662306a36Sopenharmony_ci u32 *base_offset) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct bfa_flash_attr *flash_attr; 89962306a36Sopenharmony_ci struct bnad_iocmd_comp fcomp; 90062306a36Sopenharmony_ci u32 i, flash_part = 0, ret; 90162306a36Sopenharmony_ci unsigned long flags = 0; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci flash_attr = kzalloc(sizeof(struct bfa_flash_attr), GFP_KERNEL); 90462306a36Sopenharmony_ci if (!flash_attr) 90562306a36Sopenharmony_ci return 0; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci fcomp.bnad = bnad; 90862306a36Sopenharmony_ci fcomp.comp_status = 0; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci init_completion(&fcomp.comp); 91162306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 91262306a36Sopenharmony_ci ret = bfa_nw_flash_get_attr(&bnad->bna.flash, flash_attr, 91362306a36Sopenharmony_ci bnad_cb_completion, &fcomp); 91462306a36Sopenharmony_ci if (ret != BFA_STATUS_OK) { 91562306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 91662306a36Sopenharmony_ci kfree(flash_attr); 91762306a36Sopenharmony_ci return 0; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 92062306a36Sopenharmony_ci wait_for_completion(&fcomp.comp); 92162306a36Sopenharmony_ci ret = fcomp.comp_status; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* Check for the flash type & base offset value */ 92462306a36Sopenharmony_ci if (ret == BFA_STATUS_OK) { 92562306a36Sopenharmony_ci for (i = 0; i < flash_attr->npart; i++) { 92662306a36Sopenharmony_ci if (offset >= flash_attr->part[i].part_off && 92762306a36Sopenharmony_ci offset < (flash_attr->part[i].part_off + 92862306a36Sopenharmony_ci flash_attr->part[i].part_size)) { 92962306a36Sopenharmony_ci flash_part = flash_attr->part[i].part_type; 93062306a36Sopenharmony_ci *base_offset = flash_attr->part[i].part_off; 93162306a36Sopenharmony_ci break; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci kfree(flash_attr); 93662306a36Sopenharmony_ci return flash_part; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic int 94062306a36Sopenharmony_cibnad_get_eeprom_len(struct net_device *netdev) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci return BFA_TOTAL_FLASH_SIZE; 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic int 94662306a36Sopenharmony_cibnad_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, 94762306a36Sopenharmony_ci u8 *bytes) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 95062306a36Sopenharmony_ci struct bnad_iocmd_comp fcomp; 95162306a36Sopenharmony_ci u32 flash_part = 0, base_offset = 0; 95262306a36Sopenharmony_ci unsigned long flags = 0; 95362306a36Sopenharmony_ci int ret = 0; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* Fill the magic value */ 95662306a36Sopenharmony_ci eeprom->magic = bnad->pcidev->vendor | (bnad->pcidev->device << 16); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* Query the flash partition based on the offset */ 95962306a36Sopenharmony_ci flash_part = bnad_get_flash_partition_by_offset(bnad, 96062306a36Sopenharmony_ci eeprom->offset, &base_offset); 96162306a36Sopenharmony_ci if (flash_part == 0) 96262306a36Sopenharmony_ci return -EFAULT; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci fcomp.bnad = bnad; 96562306a36Sopenharmony_ci fcomp.comp_status = 0; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci init_completion(&fcomp.comp); 96862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 96962306a36Sopenharmony_ci ret = bfa_nw_flash_read_part(&bnad->bna.flash, flash_part, 97062306a36Sopenharmony_ci bnad->id, bytes, eeprom->len, 97162306a36Sopenharmony_ci eeprom->offset - base_offset, 97262306a36Sopenharmony_ci bnad_cb_completion, &fcomp); 97362306a36Sopenharmony_ci if (ret != BFA_STATUS_OK) { 97462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 97562306a36Sopenharmony_ci goto done; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 97962306a36Sopenharmony_ci wait_for_completion(&fcomp.comp); 98062306a36Sopenharmony_ci ret = fcomp.comp_status; 98162306a36Sopenharmony_cidone: 98262306a36Sopenharmony_ci return ret; 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic int 98662306a36Sopenharmony_cibnad_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, 98762306a36Sopenharmony_ci u8 *bytes) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 99062306a36Sopenharmony_ci struct bnad_iocmd_comp fcomp; 99162306a36Sopenharmony_ci u32 flash_part = 0, base_offset = 0; 99262306a36Sopenharmony_ci unsigned long flags = 0; 99362306a36Sopenharmony_ci int ret = 0; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Check if the flash update request is valid */ 99662306a36Sopenharmony_ci if (eeprom->magic != (bnad->pcidev->vendor | 99762306a36Sopenharmony_ci (bnad->pcidev->device << 16))) 99862306a36Sopenharmony_ci return -EINVAL; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Query the flash partition based on the offset */ 100162306a36Sopenharmony_ci flash_part = bnad_get_flash_partition_by_offset(bnad, 100262306a36Sopenharmony_ci eeprom->offset, &base_offset); 100362306a36Sopenharmony_ci if (flash_part == 0) 100462306a36Sopenharmony_ci return -EFAULT; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci fcomp.bnad = bnad; 100762306a36Sopenharmony_ci fcomp.comp_status = 0; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci init_completion(&fcomp.comp); 101062306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 101162306a36Sopenharmony_ci ret = bfa_nw_flash_update_part(&bnad->bna.flash, flash_part, 101262306a36Sopenharmony_ci bnad->id, bytes, eeprom->len, 101362306a36Sopenharmony_ci eeprom->offset - base_offset, 101462306a36Sopenharmony_ci bnad_cb_completion, &fcomp); 101562306a36Sopenharmony_ci if (ret != BFA_STATUS_OK) { 101662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 101762306a36Sopenharmony_ci goto done; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 102162306a36Sopenharmony_ci wait_for_completion(&fcomp.comp); 102262306a36Sopenharmony_ci ret = fcomp.comp_status; 102362306a36Sopenharmony_cidone: 102462306a36Sopenharmony_ci return ret; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic int 102862306a36Sopenharmony_cibnad_flash_device(struct net_device *netdev, struct ethtool_flash *eflash) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 103162306a36Sopenharmony_ci struct bnad_iocmd_comp fcomp; 103262306a36Sopenharmony_ci const struct firmware *fw; 103362306a36Sopenharmony_ci int ret = 0; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci ret = request_firmware(&fw, eflash->data, &bnad->pcidev->dev); 103662306a36Sopenharmony_ci if (ret) { 103762306a36Sopenharmony_ci netdev_err(netdev, "can't load firmware %s\n", eflash->data); 103862306a36Sopenharmony_ci goto out; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci fcomp.bnad = bnad; 104262306a36Sopenharmony_ci fcomp.comp_status = 0; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci init_completion(&fcomp.comp); 104562306a36Sopenharmony_ci spin_lock_irq(&bnad->bna_lock); 104662306a36Sopenharmony_ci ret = bfa_nw_flash_update_part(&bnad->bna.flash, BFA_FLASH_PART_FWIMG, 104762306a36Sopenharmony_ci bnad->id, (u8 *)fw->data, fw->size, 0, 104862306a36Sopenharmony_ci bnad_cb_completion, &fcomp); 104962306a36Sopenharmony_ci if (ret != BFA_STATUS_OK) { 105062306a36Sopenharmony_ci netdev_warn(netdev, "flash update failed with err=%d\n", ret); 105162306a36Sopenharmony_ci ret = -EIO; 105262306a36Sopenharmony_ci spin_unlock_irq(&bnad->bna_lock); 105362306a36Sopenharmony_ci goto out; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci spin_unlock_irq(&bnad->bna_lock); 105762306a36Sopenharmony_ci wait_for_completion(&fcomp.comp); 105862306a36Sopenharmony_ci if (fcomp.comp_status != BFA_STATUS_OK) { 105962306a36Sopenharmony_ci ret = -EIO; 106062306a36Sopenharmony_ci netdev_warn(netdev, 106162306a36Sopenharmony_ci "firmware image update failed with err=%d\n", 106262306a36Sopenharmony_ci fcomp.comp_status); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ciout: 106562306a36Sopenharmony_ci release_firmware(fw); 106662306a36Sopenharmony_ci return ret; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic const struct ethtool_ops bnad_ethtool_ops = { 107062306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 107162306a36Sopenharmony_ci ETHTOOL_COALESCE_TX_MAX_FRAMES | 107262306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 107362306a36Sopenharmony_ci .get_drvinfo = bnad_get_drvinfo, 107462306a36Sopenharmony_ci .get_wol = bnad_get_wol, 107562306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 107662306a36Sopenharmony_ci .get_coalesce = bnad_get_coalesce, 107762306a36Sopenharmony_ci .set_coalesce = bnad_set_coalesce, 107862306a36Sopenharmony_ci .get_ringparam = bnad_get_ringparam, 107962306a36Sopenharmony_ci .set_ringparam = bnad_set_ringparam, 108062306a36Sopenharmony_ci .get_pauseparam = bnad_get_pauseparam, 108162306a36Sopenharmony_ci .set_pauseparam = bnad_set_pauseparam, 108262306a36Sopenharmony_ci .get_strings = bnad_get_strings, 108362306a36Sopenharmony_ci .get_ethtool_stats = bnad_get_ethtool_stats, 108462306a36Sopenharmony_ci .get_sset_count = bnad_get_sset_count, 108562306a36Sopenharmony_ci .get_eeprom_len = bnad_get_eeprom_len, 108662306a36Sopenharmony_ci .get_eeprom = bnad_get_eeprom, 108762306a36Sopenharmony_ci .set_eeprom = bnad_set_eeprom, 108862306a36Sopenharmony_ci .flash_device = bnad_flash_device, 108962306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 109062306a36Sopenharmony_ci .get_link_ksettings = bnad_get_link_ksettings, 109162306a36Sopenharmony_ci .set_link_ksettings = bnad_set_link_ksettings, 109262306a36Sopenharmony_ci}; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_civoid 109562306a36Sopenharmony_cibnad_set_ethtool_ops(struct net_device *netdev) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci netdev->ethtool_ops = &bnad_ethtool_ops; 109862306a36Sopenharmony_ci} 1099