18c2ecf20Sopenharmony_ci/* bnx2x_ethtool.c: QLogic Everest network driver. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2013 Broadcom Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2014 QLogic Corporation 58c2ecf20Sopenharmony_ci * All rights reserved 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 88c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 98c2ecf20Sopenharmony_ci * the Free Software Foundation. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com> 128c2ecf20Sopenharmony_ci * Written by: Eliezer Tamir 138c2ecf20Sopenharmony_ci * Based on code from Michael Chan's bnx2 driver 148c2ecf20Sopenharmony_ci * UDP CSUM errata workaround by Arik Gendelman 158c2ecf20Sopenharmony_ci * Slowpath and fastpath rework by Vladislav Zolotarov 168c2ecf20Sopenharmony_ci * Statistics and Link management by Yitchak Gertner 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 238c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 248c2ecf20Sopenharmony_ci#include <linux/types.h> 258c2ecf20Sopenharmony_ci#include <linux/sched.h> 268c2ecf20Sopenharmony_ci#include <linux/crc32.h> 278c2ecf20Sopenharmony_ci#include "bnx2x.h" 288c2ecf20Sopenharmony_ci#include "bnx2x_cmn.h" 298c2ecf20Sopenharmony_ci#include "bnx2x_dump.h" 308c2ecf20Sopenharmony_ci#include "bnx2x_init.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Note: in the format strings below %s is replaced by the queue-name which is 338c2ecf20Sopenharmony_ci * either its index or 'fcoe' for the fcoe queue. Make sure the format string 348c2ecf20Sopenharmony_ci * length does not exceed ETH_GSTRING_LEN - MAX_QUEUE_NAME_LEN + 2 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#define MAX_QUEUE_NAME_LEN 4 378c2ecf20Sopenharmony_cistatic const struct { 388c2ecf20Sopenharmony_ci long offset; 398c2ecf20Sopenharmony_ci int size; 408c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 418c2ecf20Sopenharmony_ci} bnx2x_q_stats_arr[] = { 428c2ecf20Sopenharmony_ci/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%s]: rx_bytes" }, 438c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_unicast_packets_received_hi), 448c2ecf20Sopenharmony_ci 8, "[%s]: rx_ucast_packets" }, 458c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_multicast_packets_received_hi), 468c2ecf20Sopenharmony_ci 8, "[%s]: rx_mcast_packets" }, 478c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_broadcast_packets_received_hi), 488c2ecf20Sopenharmony_ci 8, "[%s]: rx_bcast_packets" }, 498c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%s]: rx_discards" }, 508c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(rx_err_discard_pkt), 518c2ecf20Sopenharmony_ci 4, "[%s]: rx_phy_ip_err_discards"}, 528c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(rx_skb_alloc_failed), 538c2ecf20Sopenharmony_ci 4, "[%s]: rx_skb_alloc_discard" }, 548c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(hw_csum_err), 4, "[%s]: rx_csum_offload_errors" }, 558c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(driver_xoff), 4, "[%s]: tx_exhaustion_events" }, 568c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%s]: tx_bytes" }, 578c2ecf20Sopenharmony_ci/* 10 */{ Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi), 588c2ecf20Sopenharmony_ci 8, "[%s]: tx_ucast_packets" }, 598c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi), 608c2ecf20Sopenharmony_ci 8, "[%s]: tx_mcast_packets" }, 618c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi), 628c2ecf20Sopenharmony_ci 8, "[%s]: tx_bcast_packets" }, 638c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_tpa_aggregations_hi), 648c2ecf20Sopenharmony_ci 8, "[%s]: tpa_aggregations" }, 658c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_tpa_aggregated_frames_hi), 668c2ecf20Sopenharmony_ci 8, "[%s]: tpa_aggregated_frames"}, 678c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(total_tpa_bytes_hi), 8, "[%s]: tpa_bytes"}, 688c2ecf20Sopenharmony_ci { Q_STATS_OFFSET32(driver_filtered_tx_pkt), 698c2ecf20Sopenharmony_ci 4, "[%s]: driver_filtered_tx_pkt" } 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define BNX2X_NUM_Q_STATS ARRAY_SIZE(bnx2x_q_stats_arr) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const struct { 758c2ecf20Sopenharmony_ci long offset; 768c2ecf20Sopenharmony_ci int size; 778c2ecf20Sopenharmony_ci bool is_port_stat; 788c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 798c2ecf20Sopenharmony_ci} bnx2x_stats_arr[] = { 808c2ecf20Sopenharmony_ci/* 1 */ { STATS_OFFSET32(total_bytes_received_hi), 818c2ecf20Sopenharmony_ci 8, false, "rx_bytes" }, 828c2ecf20Sopenharmony_ci { STATS_OFFSET32(error_bytes_received_hi), 838c2ecf20Sopenharmony_ci 8, false, "rx_error_bytes" }, 848c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_unicast_packets_received_hi), 858c2ecf20Sopenharmony_ci 8, false, "rx_ucast_packets" }, 868c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_multicast_packets_received_hi), 878c2ecf20Sopenharmony_ci 8, false, "rx_mcast_packets" }, 888c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_broadcast_packets_received_hi), 898c2ecf20Sopenharmony_ci 8, false, "rx_bcast_packets" }, 908c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi), 918c2ecf20Sopenharmony_ci 8, true, "rx_crc_errors" }, 928c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi), 938c2ecf20Sopenharmony_ci 8, true, "rx_align_errors" }, 948c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi), 958c2ecf20Sopenharmony_ci 8, true, "rx_undersize_packets" }, 968c2ecf20Sopenharmony_ci { STATS_OFFSET32(etherstatsoverrsizepkts_hi), 978c2ecf20Sopenharmony_ci 8, true, "rx_oversize_packets" }, 988c2ecf20Sopenharmony_ci/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi), 998c2ecf20Sopenharmony_ci 8, true, "rx_fragments" }, 1008c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi), 1018c2ecf20Sopenharmony_ci 8, true, "rx_jabbers" }, 1028c2ecf20Sopenharmony_ci { STATS_OFFSET32(no_buff_discard_hi), 1038c2ecf20Sopenharmony_ci 8, false, "rx_discards" }, 1048c2ecf20Sopenharmony_ci { STATS_OFFSET32(mac_filter_discard), 1058c2ecf20Sopenharmony_ci 4, true, "rx_filtered_packets" }, 1068c2ecf20Sopenharmony_ci { STATS_OFFSET32(mf_tag_discard), 1078c2ecf20Sopenharmony_ci 4, true, "rx_mf_tag_discard" }, 1088c2ecf20Sopenharmony_ci { STATS_OFFSET32(pfc_frames_received_hi), 1098c2ecf20Sopenharmony_ci 8, true, "pfc_frames_received" }, 1108c2ecf20Sopenharmony_ci { STATS_OFFSET32(pfc_frames_sent_hi), 1118c2ecf20Sopenharmony_ci 8, true, "pfc_frames_sent" }, 1128c2ecf20Sopenharmony_ci { STATS_OFFSET32(brb_drop_hi), 1138c2ecf20Sopenharmony_ci 8, true, "rx_brb_discard" }, 1148c2ecf20Sopenharmony_ci { STATS_OFFSET32(brb_truncate_hi), 1158c2ecf20Sopenharmony_ci 8, true, "rx_brb_truncate" }, 1168c2ecf20Sopenharmony_ci { STATS_OFFSET32(pause_frames_received_hi), 1178c2ecf20Sopenharmony_ci 8, true, "rx_pause_frames" }, 1188c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi), 1198c2ecf20Sopenharmony_ci 8, true, "rx_mac_ctrl_frames" }, 1208c2ecf20Sopenharmony_ci { STATS_OFFSET32(nig_timer_max), 1218c2ecf20Sopenharmony_ci 4, true, "rx_constant_pause_events" }, 1228c2ecf20Sopenharmony_ci/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt), 1238c2ecf20Sopenharmony_ci 4, false, "rx_phy_ip_err_discards"}, 1248c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_skb_alloc_failed), 1258c2ecf20Sopenharmony_ci 4, false, "rx_skb_alloc_discard" }, 1268c2ecf20Sopenharmony_ci { STATS_OFFSET32(hw_csum_err), 1278c2ecf20Sopenharmony_ci 4, false, "rx_csum_offload_errors" }, 1288c2ecf20Sopenharmony_ci { STATS_OFFSET32(driver_xoff), 1298c2ecf20Sopenharmony_ci 4, false, "tx_exhaustion_events" }, 1308c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_bytes_transmitted_hi), 1318c2ecf20Sopenharmony_ci 8, false, "tx_bytes" }, 1328c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi), 1338c2ecf20Sopenharmony_ci 8, true, "tx_error_bytes" }, 1348c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_unicast_packets_transmitted_hi), 1358c2ecf20Sopenharmony_ci 8, false, "tx_ucast_packets" }, 1368c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_multicast_packets_transmitted_hi), 1378c2ecf20Sopenharmony_ci 8, false, "tx_mcast_packets" }, 1388c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_broadcast_packets_transmitted_hi), 1398c2ecf20Sopenharmony_ci 8, false, "tx_bcast_packets" }, 1408c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi), 1418c2ecf20Sopenharmony_ci 8, true, "tx_mac_errors" }, 1428c2ecf20Sopenharmony_ci { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi), 1438c2ecf20Sopenharmony_ci 8, true, "tx_carrier_errors" }, 1448c2ecf20Sopenharmony_ci/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi), 1458c2ecf20Sopenharmony_ci 8, true, "tx_single_collisions" }, 1468c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi), 1478c2ecf20Sopenharmony_ci 8, true, "tx_multi_collisions" }, 1488c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi), 1498c2ecf20Sopenharmony_ci 8, true, "tx_deferred" }, 1508c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi), 1518c2ecf20Sopenharmony_ci 8, true, "tx_excess_collisions" }, 1528c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi), 1538c2ecf20Sopenharmony_ci 8, true, "tx_late_collisions" }, 1548c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_etherstatscollisions_hi), 1558c2ecf20Sopenharmony_ci 8, true, "tx_total_collisions" }, 1568c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi), 1578c2ecf20Sopenharmony_ci 8, true, "tx_64_byte_packets" }, 1588c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi), 1598c2ecf20Sopenharmony_ci 8, true, "tx_65_to_127_byte_packets" }, 1608c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi), 1618c2ecf20Sopenharmony_ci 8, true, "tx_128_to_255_byte_packets" }, 1628c2ecf20Sopenharmony_ci { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi), 1638c2ecf20Sopenharmony_ci 8, true, "tx_256_to_511_byte_packets" }, 1648c2ecf20Sopenharmony_ci/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi), 1658c2ecf20Sopenharmony_ci 8, true, "tx_512_to_1023_byte_packets" }, 1668c2ecf20Sopenharmony_ci { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi), 1678c2ecf20Sopenharmony_ci 8, true, "tx_1024_to_1522_byte_packets" }, 1688c2ecf20Sopenharmony_ci { STATS_OFFSET32(etherstatspktsover1522octets_hi), 1698c2ecf20Sopenharmony_ci 8, true, "tx_1523_to_9022_byte_packets" }, 1708c2ecf20Sopenharmony_ci { STATS_OFFSET32(pause_frames_sent_hi), 1718c2ecf20Sopenharmony_ci 8, true, "tx_pause_frames" }, 1728c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_tpa_aggregations_hi), 1738c2ecf20Sopenharmony_ci 8, false, "tpa_aggregations" }, 1748c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_tpa_aggregated_frames_hi), 1758c2ecf20Sopenharmony_ci 8, false, "tpa_aggregated_frames"}, 1768c2ecf20Sopenharmony_ci { STATS_OFFSET32(total_tpa_bytes_hi), 1778c2ecf20Sopenharmony_ci 8, false, "tpa_bytes"}, 1788c2ecf20Sopenharmony_ci { STATS_OFFSET32(recoverable_error), 1798c2ecf20Sopenharmony_ci 4, false, "recoverable_errors" }, 1808c2ecf20Sopenharmony_ci { STATS_OFFSET32(unrecoverable_error), 1818c2ecf20Sopenharmony_ci 4, false, "unrecoverable_errors" }, 1828c2ecf20Sopenharmony_ci { STATS_OFFSET32(driver_filtered_tx_pkt), 1838c2ecf20Sopenharmony_ci 4, false, "driver_filtered_tx_pkt" }, 1848c2ecf20Sopenharmony_ci { STATS_OFFSET32(eee_tx_lpi), 1858c2ecf20Sopenharmony_ci 4, true, "Tx LPI entry count"}, 1868c2ecf20Sopenharmony_ci { STATS_OFFSET32(ptp_skip_tx_ts), 1878c2ecf20Sopenharmony_ci 4, false, "ptp_skipped_tx_tstamp" }, 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int bnx2x_get_port_type(struct bnx2x *bp) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci int port_type; 1958c2ecf20Sopenharmony_ci u32 phy_idx = bnx2x_get_cur_phy_idx(bp); 1968c2ecf20Sopenharmony_ci switch (bp->link_params.phy[phy_idx].media_type) { 1978c2ecf20Sopenharmony_ci case ETH_PHY_SFPP_10G_FIBER: 1988c2ecf20Sopenharmony_ci case ETH_PHY_SFP_1G_FIBER: 1998c2ecf20Sopenharmony_ci case ETH_PHY_XFP_FIBER: 2008c2ecf20Sopenharmony_ci case ETH_PHY_KR: 2018c2ecf20Sopenharmony_ci case ETH_PHY_CX4: 2028c2ecf20Sopenharmony_ci port_type = PORT_FIBRE; 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case ETH_PHY_DA_TWINAX: 2058c2ecf20Sopenharmony_ci port_type = PORT_DA; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case ETH_PHY_BASE_T: 2088c2ecf20Sopenharmony_ci port_type = PORT_TP; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case ETH_PHY_NOT_PRESENT: 2118c2ecf20Sopenharmony_ci port_type = PORT_NONE; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case ETH_PHY_UNSPECIFIED: 2148c2ecf20Sopenharmony_ci default: 2158c2ecf20Sopenharmony_ci port_type = PORT_OTHER; 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci return port_type; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int bnx2x_get_vf_link_ksettings(struct net_device *dev, 2228c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 2258c2ecf20Sopenharmony_ci u32 supported, advertising; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&supported, 2288c2ecf20Sopenharmony_ci cmd->link_modes.supported); 2298c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&advertising, 2308c2ecf20Sopenharmony_ci cmd->link_modes.advertising); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) { 2338c2ecf20Sopenharmony_ci if (test_bit(BNX2X_LINK_REPORT_FD, 2348c2ecf20Sopenharmony_ci &bp->vf_link_vars.link_report_flags)) 2358c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_HALF; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci cmd->base.speed = bp->vf_link_vars.line_speed; 2408c2ecf20Sopenharmony_ci } else { 2418c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 2428c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci cmd->base.port = PORT_OTHER; 2468c2ecf20Sopenharmony_ci cmd->base.phy_address = 0; 2478c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "ethtool_cmd: cmd %d\n" 2508c2ecf20Sopenharmony_ci " supported 0x%x advertising 0x%x speed %u\n" 2518c2ecf20Sopenharmony_ci " duplex %d port %d phy_address %d\n" 2528c2ecf20Sopenharmony_ci " autoneg %d\n", 2538c2ecf20Sopenharmony_ci cmd->base.cmd, supported, advertising, 2548c2ecf20Sopenharmony_ci cmd->base.speed, 2558c2ecf20Sopenharmony_ci cmd->base.duplex, cmd->base.port, cmd->base.phy_address, 2568c2ecf20Sopenharmony_ci cmd->base.autoneg); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int bnx2x_get_link_ksettings(struct net_device *dev, 2628c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 2658c2ecf20Sopenharmony_ci int cfg_idx = bnx2x_get_link_cfg_idx(bp); 2668c2ecf20Sopenharmony_ci u32 media_type; 2678c2ecf20Sopenharmony_ci u32 supported, advertising, lp_advertising; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&lp_advertising, 2708c2ecf20Sopenharmony_ci cmd->link_modes.lp_advertising); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Dual Media boards present all available port types */ 2738c2ecf20Sopenharmony_ci supported = bp->port.supported[cfg_idx] | 2748c2ecf20Sopenharmony_ci (bp->port.supported[cfg_idx ^ 1] & 2758c2ecf20Sopenharmony_ci (SUPPORTED_TP | SUPPORTED_FIBRE)); 2768c2ecf20Sopenharmony_ci advertising = bp->port.advertising[cfg_idx]; 2778c2ecf20Sopenharmony_ci media_type = bp->link_params.phy[bnx2x_get_cur_phy_idx(bp)].media_type; 2788c2ecf20Sopenharmony_ci if (media_type == ETH_PHY_SFP_1G_FIBER) { 2798c2ecf20Sopenharmony_ci supported &= ~(SUPPORTED_10000baseT_Full); 2808c2ecf20Sopenharmony_ci advertising &= ~(ADVERTISED_10000baseT_Full); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if ((bp->state == BNX2X_STATE_OPEN) && bp->link_vars.link_up && 2848c2ecf20Sopenharmony_ci !(bp->flags & MF_FUNC_DIS)) { 2858c2ecf20Sopenharmony_ci cmd->base.duplex = bp->link_vars.duplex; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (IS_MF(bp) && !BP_NOMCP(bp)) 2888c2ecf20Sopenharmony_ci cmd->base.speed = bnx2x_get_mf_speed(bp); 2898c2ecf20Sopenharmony_ci else 2908c2ecf20Sopenharmony_ci cmd->base.speed = bp->link_vars.line_speed; 2918c2ecf20Sopenharmony_ci } else { 2928c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 2938c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci cmd->base.port = bnx2x_get_port_type(bp); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci cmd->base.phy_address = bp->mdio.prtad; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) 3018c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Publish LP advertised speeds and FC */ 3068c2ecf20Sopenharmony_ci if (bp->link_vars.link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) { 3078c2ecf20Sopenharmony_ci u32 status = bp->link_vars.link_status; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_Autoneg; 3108c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE) 3118c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_Pause; 3128c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE) 3138c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_Asym_Pause; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_10THD_CAPABLE) 3168c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_10baseT_Half; 3178c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE) 3188c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_10baseT_Full; 3198c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE) 3208c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_100baseT_Half; 3218c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE) 3228c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_100baseT_Full; 3238c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) 3248c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_1000baseT_Half; 3258c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) { 3268c2ecf20Sopenharmony_ci if (media_type == ETH_PHY_KR) { 3278c2ecf20Sopenharmony_ci lp_advertising |= 3288c2ecf20Sopenharmony_ci ADVERTISED_1000baseKX_Full; 3298c2ecf20Sopenharmony_ci } else { 3308c2ecf20Sopenharmony_ci lp_advertising |= 3318c2ecf20Sopenharmony_ci ADVERTISED_1000baseT_Full; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE) 3358c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_2500baseX_Full; 3368c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE) { 3378c2ecf20Sopenharmony_ci if (media_type == ETH_PHY_KR) { 3388c2ecf20Sopenharmony_ci lp_advertising |= 3398c2ecf20Sopenharmony_ci ADVERTISED_10000baseKR_Full; 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci lp_advertising |= 3428c2ecf20Sopenharmony_ci ADVERTISED_10000baseT_Full; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci if (status & LINK_STATUS_LINK_PARTNER_20GXFD_CAPABLE) 3468c2ecf20Sopenharmony_ci lp_advertising |= ADVERTISED_20000baseKR2_Full; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 3508c2ecf20Sopenharmony_ci supported); 3518c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 3528c2ecf20Sopenharmony_ci advertising); 3538c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, 3548c2ecf20Sopenharmony_ci lp_advertising); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "ethtool_cmd: cmd %d\n" 3578c2ecf20Sopenharmony_ci " supported 0x%x advertising 0x%x speed %u\n" 3588c2ecf20Sopenharmony_ci " duplex %d port %d phy_address %d\n" 3598c2ecf20Sopenharmony_ci " autoneg %d\n", 3608c2ecf20Sopenharmony_ci cmd->base.cmd, supported, advertising, 3618c2ecf20Sopenharmony_ci cmd->base.speed, 3628c2ecf20Sopenharmony_ci cmd->base.duplex, cmd->base.port, cmd->base.phy_address, 3638c2ecf20Sopenharmony_ci cmd->base.autoneg); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int bnx2x_set_link_ksettings(struct net_device *dev, 3698c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 3728c2ecf20Sopenharmony_ci u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config; 3738c2ecf20Sopenharmony_ci u32 speed, phy_idx; 3748c2ecf20Sopenharmony_ci u32 supported; 3758c2ecf20Sopenharmony_ci u8 duplex = cmd->base.duplex; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&supported, 3788c2ecf20Sopenharmony_ci cmd->link_modes.supported); 3798c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32(&advertising, 3808c2ecf20Sopenharmony_ci cmd->link_modes.advertising); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (IS_MF_SD(bp)) 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "ethtool_cmd: cmd %d\n" 3868c2ecf20Sopenharmony_ci " supported 0x%x advertising 0x%x speed %u\n" 3878c2ecf20Sopenharmony_ci " duplex %d port %d phy_address %d\n" 3888c2ecf20Sopenharmony_ci " autoneg %d\n", 3898c2ecf20Sopenharmony_ci cmd->base.cmd, supported, advertising, 3908c2ecf20Sopenharmony_ci cmd->base.speed, 3918c2ecf20Sopenharmony_ci cmd->base.duplex, cmd->base.port, cmd->base.phy_address, 3928c2ecf20Sopenharmony_ci cmd->base.autoneg); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci speed = cmd->base.speed; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* If received a request for an unknown duplex, assume full*/ 3978c2ecf20Sopenharmony_ci if (duplex == DUPLEX_UNKNOWN) 3988c2ecf20Sopenharmony_ci duplex = DUPLEX_FULL; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (IS_MF_SI(bp)) { 4018c2ecf20Sopenharmony_ci u32 part; 4028c2ecf20Sopenharmony_ci u32 line_speed = bp->link_vars.line_speed; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* use 10G if no link detected */ 4058c2ecf20Sopenharmony_ci if (!line_speed) 4068c2ecf20Sopenharmony_ci line_speed = 10000; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (bp->common.bc_ver < REQ_BC_VER_4_SET_MF_BW) { 4098c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 4108c2ecf20Sopenharmony_ci "To set speed BC %X or higher is required, please upgrade BC\n", 4118c2ecf20Sopenharmony_ci REQ_BC_VER_4_SET_MF_BW); 4128c2ecf20Sopenharmony_ci return -EINVAL; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci part = (speed * 100) / line_speed; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (line_speed < speed || !part) { 4188c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 4198c2ecf20Sopenharmony_ci "Speed setting should be in a range from 1%% to 100%% of actual line speed\n"); 4208c2ecf20Sopenharmony_ci return -EINVAL; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (bp->state != BNX2X_STATE_OPEN) 4248c2ecf20Sopenharmony_ci /* store value for following "load" */ 4258c2ecf20Sopenharmony_ci bp->pending_max = part; 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci bnx2x_update_max_mf_config(bp, part); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci cfg_idx = bnx2x_get_link_cfg_idx(bp); 4338c2ecf20Sopenharmony_ci old_multi_phy_config = bp->link_params.multi_phy_config; 4348c2ecf20Sopenharmony_ci if (cmd->base.port != bnx2x_get_port_type(bp)) { 4358c2ecf20Sopenharmony_ci switch (cmd->base.port) { 4368c2ecf20Sopenharmony_ci case PORT_TP: 4378c2ecf20Sopenharmony_ci if (!(bp->port.supported[0] & SUPPORTED_TP || 4388c2ecf20Sopenharmony_ci bp->port.supported[1] & SUPPORTED_TP)) { 4398c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 4408c2ecf20Sopenharmony_ci "Unsupported port type\n"); 4418c2ecf20Sopenharmony_ci return -EINVAL; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config &= 4448c2ecf20Sopenharmony_ci ~PORT_HW_CFG_PHY_SELECTION_MASK; 4458c2ecf20Sopenharmony_ci if (bp->link_params.multi_phy_config & 4468c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SWAPPED_ENABLED) 4478c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config |= 4488c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; 4498c2ecf20Sopenharmony_ci else 4508c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config |= 4518c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; 4528c2ecf20Sopenharmony_ci break; 4538c2ecf20Sopenharmony_ci case PORT_FIBRE: 4548c2ecf20Sopenharmony_ci case PORT_DA: 4558c2ecf20Sopenharmony_ci case PORT_NONE: 4568c2ecf20Sopenharmony_ci if (!(bp->port.supported[0] & SUPPORTED_FIBRE || 4578c2ecf20Sopenharmony_ci bp->port.supported[1] & SUPPORTED_FIBRE)) { 4588c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 4598c2ecf20Sopenharmony_ci "Unsupported port type\n"); 4608c2ecf20Sopenharmony_ci return -EINVAL; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config &= 4638c2ecf20Sopenharmony_ci ~PORT_HW_CFG_PHY_SELECTION_MASK; 4648c2ecf20Sopenharmony_ci if (bp->link_params.multi_phy_config & 4658c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SWAPPED_ENABLED) 4668c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config |= 4678c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; 4688c2ecf20Sopenharmony_ci else 4698c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config |= 4708c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci default: 4738c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n"); 4748c2ecf20Sopenharmony_ci return -EINVAL; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci /* Save new config in case command complete successfully */ 4788c2ecf20Sopenharmony_ci new_multi_phy_config = bp->link_params.multi_phy_config; 4798c2ecf20Sopenharmony_ci /* Get the new cfg_idx */ 4808c2ecf20Sopenharmony_ci cfg_idx = bnx2x_get_link_cfg_idx(bp); 4818c2ecf20Sopenharmony_ci /* Restore old config in case command failed */ 4828c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config = old_multi_phy_config; 4838c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "cfg_idx = %x\n", cfg_idx); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_ENABLE) { 4868c2ecf20Sopenharmony_ci u32 an_supported_speed = bp->port.supported[cfg_idx]; 4878c2ecf20Sopenharmony_ci if (bp->link_params.phy[EXT_PHY1].type == 4888c2ecf20Sopenharmony_ci PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) 4898c2ecf20Sopenharmony_ci an_supported_speed |= (SUPPORTED_100baseT_Half | 4908c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Full); 4918c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) { 4928c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Autoneg not supported\n"); 4938c2ecf20Sopenharmony_ci return -EINVAL; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* advertise the requested speed and duplex if supported */ 4978c2ecf20Sopenharmony_ci if (advertising & ~an_supported_speed) { 4988c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 4998c2ecf20Sopenharmony_ci "Advertisement parameters are not supported\n"); 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG; 5048c2ecf20Sopenharmony_ci bp->link_params.req_duplex[cfg_idx] = duplex; 5058c2ecf20Sopenharmony_ci bp->port.advertising[cfg_idx] = (ADVERTISED_Autoneg | 5068c2ecf20Sopenharmony_ci advertising); 5078c2ecf20Sopenharmony_ci if (advertising) { 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] = 0; 5108c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_10baseT_Half) { 5118c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5128c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_10baseT_Full) 5158c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5168c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_100baseT_Full) 5198c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5208c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_100baseT_Half) { 5238c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5248c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_1000baseT_Half) { 5278c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5288c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_1G; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci if (advertising & (ADVERTISED_1000baseT_Full | 5318c2ecf20Sopenharmony_ci ADVERTISED_1000baseKX_Full)) 5328c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5338c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_1G; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (advertising & (ADVERTISED_10000baseT_Full | 5368c2ecf20Sopenharmony_ci ADVERTISED_10000baseKX4_Full | 5378c2ecf20Sopenharmony_ci ADVERTISED_10000baseKR_Full)) 5388c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5398c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_10G; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (advertising & ADVERTISED_20000baseKR2_Full) 5428c2ecf20Sopenharmony_ci bp->link_params.speed_cap_mask[cfg_idx] |= 5438c2ecf20Sopenharmony_ci PORT_HW_CFG_SPEED_CAPABILITY_D0_20G; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci } else { /* forced speed */ 5468c2ecf20Sopenharmony_ci /* advertise the requested speed and duplex if supported */ 5478c2ecf20Sopenharmony_ci switch (speed) { 5488c2ecf20Sopenharmony_ci case SPEED_10: 5498c2ecf20Sopenharmony_ci if (duplex == DUPLEX_FULL) { 5508c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] & 5518c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Full)) { 5528c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 5538c2ecf20Sopenharmony_ci "10M full not supported\n"); 5548c2ecf20Sopenharmony_ci return -EINVAL; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci advertising = (ADVERTISED_10baseT_Full | 5588c2ecf20Sopenharmony_ci ADVERTISED_TP); 5598c2ecf20Sopenharmony_ci } else { 5608c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] & 5618c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Half)) { 5628c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 5638c2ecf20Sopenharmony_ci "10M half not supported\n"); 5648c2ecf20Sopenharmony_ci return -EINVAL; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci advertising = (ADVERTISED_10baseT_Half | 5688c2ecf20Sopenharmony_ci ADVERTISED_TP); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci case SPEED_100: 5738c2ecf20Sopenharmony_ci if (duplex == DUPLEX_FULL) { 5748c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] & 5758c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Full)) { 5768c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 5778c2ecf20Sopenharmony_ci "100M full not supported\n"); 5788c2ecf20Sopenharmony_ci return -EINVAL; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci advertising = (ADVERTISED_100baseT_Full | 5828c2ecf20Sopenharmony_ci ADVERTISED_TP); 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] & 5858c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Half)) { 5868c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 5878c2ecf20Sopenharmony_ci "100M half not supported\n"); 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci advertising = (ADVERTISED_100baseT_Half | 5928c2ecf20Sopenharmony_ci ADVERTISED_TP); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci case SPEED_1000: 5978c2ecf20Sopenharmony_ci if (duplex != DUPLEX_FULL) { 5988c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 5998c2ecf20Sopenharmony_ci "1G half not supported\n"); 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (bp->port.supported[cfg_idx] & 6048c2ecf20Sopenharmony_ci SUPPORTED_1000baseT_Full) { 6058c2ecf20Sopenharmony_ci advertising = (ADVERTISED_1000baseT_Full | 6068c2ecf20Sopenharmony_ci ADVERTISED_TP); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci } else if (bp->port.supported[cfg_idx] & 6098c2ecf20Sopenharmony_ci SUPPORTED_1000baseKX_Full) { 6108c2ecf20Sopenharmony_ci advertising = ADVERTISED_1000baseKX_Full; 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 6138c2ecf20Sopenharmony_ci "1G full not supported\n"); 6148c2ecf20Sopenharmony_ci return -EINVAL; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci case SPEED_2500: 6208c2ecf20Sopenharmony_ci if (duplex != DUPLEX_FULL) { 6218c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 6228c2ecf20Sopenharmony_ci "2.5G half not supported\n"); 6238c2ecf20Sopenharmony_ci return -EINVAL; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] 6278c2ecf20Sopenharmony_ci & SUPPORTED_2500baseX_Full)) { 6288c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 6298c2ecf20Sopenharmony_ci "2.5G full not supported\n"); 6308c2ecf20Sopenharmony_ci return -EINVAL; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci advertising = (ADVERTISED_2500baseX_Full | 6348c2ecf20Sopenharmony_ci ADVERTISED_TP); 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci case SPEED_10000: 6388c2ecf20Sopenharmony_ci if (duplex != DUPLEX_FULL) { 6398c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 6408c2ecf20Sopenharmony_ci "10G half not supported\n"); 6418c2ecf20Sopenharmony_ci return -EINVAL; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci phy_idx = bnx2x_get_cur_phy_idx(bp); 6448c2ecf20Sopenharmony_ci if ((bp->port.supported[cfg_idx] & 6458c2ecf20Sopenharmony_ci SUPPORTED_10000baseT_Full) && 6468c2ecf20Sopenharmony_ci (bp->link_params.phy[phy_idx].media_type != 6478c2ecf20Sopenharmony_ci ETH_PHY_SFP_1G_FIBER)) { 6488c2ecf20Sopenharmony_ci advertising = (ADVERTISED_10000baseT_Full | 6498c2ecf20Sopenharmony_ci ADVERTISED_FIBRE); 6508c2ecf20Sopenharmony_ci } else if (bp->port.supported[cfg_idx] & 6518c2ecf20Sopenharmony_ci SUPPORTED_10000baseKR_Full) { 6528c2ecf20Sopenharmony_ci advertising = (ADVERTISED_10000baseKR_Full | 6538c2ecf20Sopenharmony_ci ADVERTISED_FIBRE); 6548c2ecf20Sopenharmony_ci } else { 6558c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 6568c2ecf20Sopenharmony_ci "10G full not supported\n"); 6578c2ecf20Sopenharmony_ci return -EINVAL; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci default: 6638c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Unsupported speed %u\n", speed); 6648c2ecf20Sopenharmony_ci return -EINVAL; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci bp->link_params.req_line_speed[cfg_idx] = speed; 6688c2ecf20Sopenharmony_ci bp->link_params.req_duplex[cfg_idx] = duplex; 6698c2ecf20Sopenharmony_ci bp->port.advertising[cfg_idx] = advertising; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "req_line_speed %d\n" 6738c2ecf20Sopenharmony_ci " req_duplex %d advertising 0x%x\n", 6748c2ecf20Sopenharmony_ci bp->link_params.req_line_speed[cfg_idx], 6758c2ecf20Sopenharmony_ci bp->link_params.req_duplex[cfg_idx], 6768c2ecf20Sopenharmony_ci bp->port.advertising[cfg_idx]); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* Set new config */ 6798c2ecf20Sopenharmony_ci bp->link_params.multi_phy_config = new_multi_phy_config; 6808c2ecf20Sopenharmony_ci if (netif_running(dev)) { 6818c2ecf20Sopenharmony_ci bnx2x_stats_handle(bp, STATS_EVENT_STOP); 6828c2ecf20Sopenharmony_ci bnx2x_force_link_reset(bp); 6838c2ecf20Sopenharmony_ci bnx2x_link_set(bp); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci#define DUMP_ALL_PRESETS 0x1FFF 6908c2ecf20Sopenharmony_ci#define DUMP_MAX_PRESETS 13 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int __bnx2x_get_preset_regs_len(struct bnx2x *bp, u32 preset) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) 6958c2ecf20Sopenharmony_ci return dump_num_registers[0][preset-1]; 6968c2ecf20Sopenharmony_ci else if (CHIP_IS_E1H(bp)) 6978c2ecf20Sopenharmony_ci return dump_num_registers[1][preset-1]; 6988c2ecf20Sopenharmony_ci else if (CHIP_IS_E2(bp)) 6998c2ecf20Sopenharmony_ci return dump_num_registers[2][preset-1]; 7008c2ecf20Sopenharmony_ci else if (CHIP_IS_E3A0(bp)) 7018c2ecf20Sopenharmony_ci return dump_num_registers[3][preset-1]; 7028c2ecf20Sopenharmony_ci else if (CHIP_IS_E3B0(bp)) 7038c2ecf20Sopenharmony_ci return dump_num_registers[4][preset-1]; 7048c2ecf20Sopenharmony_ci else 7058c2ecf20Sopenharmony_ci return 0; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int __bnx2x_get_regs_len(struct bnx2x *bp) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci u32 preset_idx; 7118c2ecf20Sopenharmony_ci int regdump_len = 0; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* Calculate the total preset regs length */ 7148c2ecf20Sopenharmony_ci for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++) 7158c2ecf20Sopenharmony_ci regdump_len += __bnx2x_get_preset_regs_len(bp, preset_idx); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return regdump_len; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic int bnx2x_get_regs_len(struct net_device *dev) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 7238c2ecf20Sopenharmony_ci int regdump_len = 0; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (IS_VF(bp)) 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci regdump_len = __bnx2x_get_regs_len(bp); 7298c2ecf20Sopenharmony_ci regdump_len *= 4; 7308c2ecf20Sopenharmony_ci regdump_len += sizeof(struct dump_header); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return regdump_len; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci#define IS_E1_REG(chips) ((chips & DUMP_CHIP_E1) == DUMP_CHIP_E1) 7368c2ecf20Sopenharmony_ci#define IS_E1H_REG(chips) ((chips & DUMP_CHIP_E1H) == DUMP_CHIP_E1H) 7378c2ecf20Sopenharmony_ci#define IS_E2_REG(chips) ((chips & DUMP_CHIP_E2) == DUMP_CHIP_E2) 7388c2ecf20Sopenharmony_ci#define IS_E3A0_REG(chips) ((chips & DUMP_CHIP_E3A0) == DUMP_CHIP_E3A0) 7398c2ecf20Sopenharmony_ci#define IS_E3B0_REG(chips) ((chips & DUMP_CHIP_E3B0) == DUMP_CHIP_E3B0) 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci#define IS_REG_IN_PRESET(presets, idx) \ 7428c2ecf20Sopenharmony_ci ((presets & (1 << (idx-1))) == (1 << (idx-1))) 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/******* Paged registers info selectors ********/ 7458c2ecf20Sopenharmony_cistatic const u32 *__bnx2x_get_page_addr_ar(struct bnx2x *bp) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp)) 7488c2ecf20Sopenharmony_ci return page_vals_e2; 7498c2ecf20Sopenharmony_ci else if (CHIP_IS_E3(bp)) 7508c2ecf20Sopenharmony_ci return page_vals_e3; 7518c2ecf20Sopenharmony_ci else 7528c2ecf20Sopenharmony_ci return NULL; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic u32 __bnx2x_get_page_reg_num(struct bnx2x *bp) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp)) 7588c2ecf20Sopenharmony_ci return PAGE_MODE_VALUES_E2; 7598c2ecf20Sopenharmony_ci else if (CHIP_IS_E3(bp)) 7608c2ecf20Sopenharmony_ci return PAGE_MODE_VALUES_E3; 7618c2ecf20Sopenharmony_ci else 7628c2ecf20Sopenharmony_ci return 0; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic const u32 *__bnx2x_get_page_write_ar(struct bnx2x *bp) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp)) 7688c2ecf20Sopenharmony_ci return page_write_regs_e2; 7698c2ecf20Sopenharmony_ci else if (CHIP_IS_E3(bp)) 7708c2ecf20Sopenharmony_ci return page_write_regs_e3; 7718c2ecf20Sopenharmony_ci else 7728c2ecf20Sopenharmony_ci return NULL; 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic u32 __bnx2x_get_page_write_num(struct bnx2x *bp) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp)) 7788c2ecf20Sopenharmony_ci return PAGE_WRITE_REGS_E2; 7798c2ecf20Sopenharmony_ci else if (CHIP_IS_E3(bp)) 7808c2ecf20Sopenharmony_ci return PAGE_WRITE_REGS_E3; 7818c2ecf20Sopenharmony_ci else 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic const struct reg_addr *__bnx2x_get_page_read_ar(struct bnx2x *bp) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp)) 7888c2ecf20Sopenharmony_ci return page_read_regs_e2; 7898c2ecf20Sopenharmony_ci else if (CHIP_IS_E3(bp)) 7908c2ecf20Sopenharmony_ci return page_read_regs_e3; 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci return NULL; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic u32 __bnx2x_get_page_read_num(struct bnx2x *bp) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp)) 7988c2ecf20Sopenharmony_ci return PAGE_READ_REGS_E2; 7998c2ecf20Sopenharmony_ci else if (CHIP_IS_E3(bp)) 8008c2ecf20Sopenharmony_ci return PAGE_READ_REGS_E3; 8018c2ecf20Sopenharmony_ci else 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic bool bnx2x_is_reg_in_chip(struct bnx2x *bp, 8068c2ecf20Sopenharmony_ci const struct reg_addr *reg_info) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) 8098c2ecf20Sopenharmony_ci return IS_E1_REG(reg_info->chips); 8108c2ecf20Sopenharmony_ci else if (CHIP_IS_E1H(bp)) 8118c2ecf20Sopenharmony_ci return IS_E1H_REG(reg_info->chips); 8128c2ecf20Sopenharmony_ci else if (CHIP_IS_E2(bp)) 8138c2ecf20Sopenharmony_ci return IS_E2_REG(reg_info->chips); 8148c2ecf20Sopenharmony_ci else if (CHIP_IS_E3A0(bp)) 8158c2ecf20Sopenharmony_ci return IS_E3A0_REG(reg_info->chips); 8168c2ecf20Sopenharmony_ci else if (CHIP_IS_E3B0(bp)) 8178c2ecf20Sopenharmony_ci return IS_E3B0_REG(reg_info->chips); 8188c2ecf20Sopenharmony_ci else 8198c2ecf20Sopenharmony_ci return false; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic bool bnx2x_is_wreg_in_chip(struct bnx2x *bp, 8238c2ecf20Sopenharmony_ci const struct wreg_addr *wreg_info) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) 8268c2ecf20Sopenharmony_ci return IS_E1_REG(wreg_info->chips); 8278c2ecf20Sopenharmony_ci else if (CHIP_IS_E1H(bp)) 8288c2ecf20Sopenharmony_ci return IS_E1H_REG(wreg_info->chips); 8298c2ecf20Sopenharmony_ci else if (CHIP_IS_E2(bp)) 8308c2ecf20Sopenharmony_ci return IS_E2_REG(wreg_info->chips); 8318c2ecf20Sopenharmony_ci else if (CHIP_IS_E3A0(bp)) 8328c2ecf20Sopenharmony_ci return IS_E3A0_REG(wreg_info->chips); 8338c2ecf20Sopenharmony_ci else if (CHIP_IS_E3B0(bp)) 8348c2ecf20Sopenharmony_ci return IS_E3B0_REG(wreg_info->chips); 8358c2ecf20Sopenharmony_ci else 8368c2ecf20Sopenharmony_ci return false; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci/** 8408c2ecf20Sopenharmony_ci * bnx2x_read_pages_regs - read "paged" registers 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * @bp: device handle 8438c2ecf20Sopenharmony_ci * @p: output buffer 8448c2ecf20Sopenharmony_ci * @preset: the preset value 8458c2ecf20Sopenharmony_ci * 8468c2ecf20Sopenharmony_ci * Reads "paged" memories: memories that may only be read by first writing to a 8478c2ecf20Sopenharmony_ci * specific address ("write address") and then reading from a specific address 8488c2ecf20Sopenharmony_ci * ("read address"). There may be more than one write address per "page" and 8498c2ecf20Sopenharmony_ci * more than one read address per write address. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_cistatic void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p, u32 preset) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci u32 i, j, k, n; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* addresses of the paged registers */ 8568c2ecf20Sopenharmony_ci const u32 *page_addr = __bnx2x_get_page_addr_ar(bp); 8578c2ecf20Sopenharmony_ci /* number of paged registers */ 8588c2ecf20Sopenharmony_ci int num_pages = __bnx2x_get_page_reg_num(bp); 8598c2ecf20Sopenharmony_ci /* write addresses */ 8608c2ecf20Sopenharmony_ci const u32 *write_addr = __bnx2x_get_page_write_ar(bp); 8618c2ecf20Sopenharmony_ci /* number of write addresses */ 8628c2ecf20Sopenharmony_ci int write_num = __bnx2x_get_page_write_num(bp); 8638c2ecf20Sopenharmony_ci /* read addresses info */ 8648c2ecf20Sopenharmony_ci const struct reg_addr *read_addr = __bnx2x_get_page_read_ar(bp); 8658c2ecf20Sopenharmony_ci /* number of read addresses */ 8668c2ecf20Sopenharmony_ci int read_num = __bnx2x_get_page_read_num(bp); 8678c2ecf20Sopenharmony_ci u32 addr, size; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci for (i = 0; i < num_pages; i++) { 8708c2ecf20Sopenharmony_ci for (j = 0; j < write_num; j++) { 8718c2ecf20Sopenharmony_ci REG_WR(bp, write_addr[j], page_addr[i]); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci for (k = 0; k < read_num; k++) { 8748c2ecf20Sopenharmony_ci if (IS_REG_IN_PRESET(read_addr[k].presets, 8758c2ecf20Sopenharmony_ci preset)) { 8768c2ecf20Sopenharmony_ci size = read_addr[k].size; 8778c2ecf20Sopenharmony_ci for (n = 0; n < size; n++) { 8788c2ecf20Sopenharmony_ci addr = read_addr[k].addr + n*4; 8798c2ecf20Sopenharmony_ci *p++ = REG_RD(bp, addr); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int __bnx2x_get_preset_regs(struct bnx2x *bp, u32 *p, u32 preset) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci u32 i, j, addr; 8908c2ecf20Sopenharmony_ci const struct wreg_addr *wreg_addr_p = NULL; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) 8938c2ecf20Sopenharmony_ci wreg_addr_p = &wreg_addr_e1; 8948c2ecf20Sopenharmony_ci else if (CHIP_IS_E1H(bp)) 8958c2ecf20Sopenharmony_ci wreg_addr_p = &wreg_addr_e1h; 8968c2ecf20Sopenharmony_ci else if (CHIP_IS_E2(bp)) 8978c2ecf20Sopenharmony_ci wreg_addr_p = &wreg_addr_e2; 8988c2ecf20Sopenharmony_ci else if (CHIP_IS_E3A0(bp)) 8998c2ecf20Sopenharmony_ci wreg_addr_p = &wreg_addr_e3; 9008c2ecf20Sopenharmony_ci else if (CHIP_IS_E3B0(bp)) 9018c2ecf20Sopenharmony_ci wreg_addr_p = &wreg_addr_e3b0; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* Read the idle_chk registers */ 9048c2ecf20Sopenharmony_ci for (i = 0; i < IDLE_REGS_COUNT; i++) { 9058c2ecf20Sopenharmony_ci if (bnx2x_is_reg_in_chip(bp, &idle_reg_addrs[i]) && 9068c2ecf20Sopenharmony_ci IS_REG_IN_PRESET(idle_reg_addrs[i].presets, preset)) { 9078c2ecf20Sopenharmony_ci for (j = 0; j < idle_reg_addrs[i].size; j++) 9088c2ecf20Sopenharmony_ci *p++ = REG_RD(bp, idle_reg_addrs[i].addr + j*4); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Read the regular registers */ 9138c2ecf20Sopenharmony_ci for (i = 0; i < REGS_COUNT; i++) { 9148c2ecf20Sopenharmony_ci if (bnx2x_is_reg_in_chip(bp, ®_addrs[i]) && 9158c2ecf20Sopenharmony_ci IS_REG_IN_PRESET(reg_addrs[i].presets, preset)) { 9168c2ecf20Sopenharmony_ci for (j = 0; j < reg_addrs[i].size; j++) 9178c2ecf20Sopenharmony_ci *p++ = REG_RD(bp, reg_addrs[i].addr + j*4); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* Read the CAM registers */ 9228c2ecf20Sopenharmony_ci if (bnx2x_is_wreg_in_chip(bp, wreg_addr_p) && 9238c2ecf20Sopenharmony_ci IS_REG_IN_PRESET(wreg_addr_p->presets, preset)) { 9248c2ecf20Sopenharmony_ci for (i = 0; i < wreg_addr_p->size; i++) { 9258c2ecf20Sopenharmony_ci *p++ = REG_RD(bp, wreg_addr_p->addr + i*4); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* In case of wreg_addr register, read additional 9288c2ecf20Sopenharmony_ci registers from read_regs array 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_ci for (j = 0; j < wreg_addr_p->read_regs_count; j++) { 9318c2ecf20Sopenharmony_ci addr = *(wreg_addr_p->read_regs); 9328c2ecf20Sopenharmony_ci *p++ = REG_RD(bp, addr + j*4); 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* Paged registers are supported in E2 & E3 only */ 9388c2ecf20Sopenharmony_ci if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) { 9398c2ecf20Sopenharmony_ci /* Read "paged" registers */ 9408c2ecf20Sopenharmony_ci bnx2x_read_pages_regs(bp, p, preset); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci return 0; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic void __bnx2x_get_regs(struct bnx2x *bp, u32 *p) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci u32 preset_idx; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* Read all registers, by reading all preset registers */ 9518c2ecf20Sopenharmony_ci for (preset_idx = 1; preset_idx <= DUMP_MAX_PRESETS; preset_idx++) { 9528c2ecf20Sopenharmony_ci /* Skip presets with IOR */ 9538c2ecf20Sopenharmony_ci if ((preset_idx == 2) || 9548c2ecf20Sopenharmony_ci (preset_idx == 5) || 9558c2ecf20Sopenharmony_ci (preset_idx == 8) || 9568c2ecf20Sopenharmony_ci (preset_idx == 11)) 9578c2ecf20Sopenharmony_ci continue; 9588c2ecf20Sopenharmony_ci __bnx2x_get_preset_regs(bp, p, preset_idx); 9598c2ecf20Sopenharmony_ci p += __bnx2x_get_preset_regs_len(bp, preset_idx); 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic void bnx2x_get_regs(struct net_device *dev, 9648c2ecf20Sopenharmony_ci struct ethtool_regs *regs, void *_p) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci u32 *p = _p; 9678c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 9688c2ecf20Sopenharmony_ci struct dump_header dump_hdr = {0}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci regs->version = 2; 9718c2ecf20Sopenharmony_ci memset(p, 0, regs->len); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 9748c2ecf20Sopenharmony_ci return; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* Disable parity attentions as long as following dump may 9778c2ecf20Sopenharmony_ci * cause false alarms by reading never written registers. We 9788c2ecf20Sopenharmony_ci * will re-enable parity attentions right after the dump. 9798c2ecf20Sopenharmony_ci */ 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci bnx2x_disable_blocks_parity(bp); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1; 9848c2ecf20Sopenharmony_ci dump_hdr.preset = DUMP_ALL_PRESETS; 9858c2ecf20Sopenharmony_ci dump_hdr.version = BNX2X_DUMP_VERSION; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* dump_meta_data presents OR of CHIP and PATH. */ 9888c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) { 9898c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E1; 9908c2ecf20Sopenharmony_ci } else if (CHIP_IS_E1H(bp)) { 9918c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E1H; 9928c2ecf20Sopenharmony_ci } else if (CHIP_IS_E2(bp)) { 9938c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E2 | 9948c2ecf20Sopenharmony_ci (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0); 9958c2ecf20Sopenharmony_ci } else if (CHIP_IS_E3A0(bp)) { 9968c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 | 9978c2ecf20Sopenharmony_ci (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0); 9988c2ecf20Sopenharmony_ci } else if (CHIP_IS_E3B0(bp)) { 9998c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 | 10008c2ecf20Sopenharmony_ci (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0); 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci memcpy(p, &dump_hdr, sizeof(struct dump_header)); 10048c2ecf20Sopenharmony_ci p += dump_hdr.header_size + 1; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* This isn't really an error, but since attention handling is going 10078c2ecf20Sopenharmony_ci * to print the GRC timeouts using this macro, we use the same. 10088c2ecf20Sopenharmony_ci */ 10098c2ecf20Sopenharmony_ci BNX2X_ERR("Generating register dump. Might trigger harmless GRC timeouts\n"); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* Actually read the registers */ 10128c2ecf20Sopenharmony_ci __bnx2x_get_regs(bp, p); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* Re-enable parity attentions */ 10158c2ecf20Sopenharmony_ci bnx2x_clear_blocks_parity(bp); 10168c2ecf20Sopenharmony_ci bnx2x_enable_blocks_parity(bp); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic int bnx2x_get_preset_regs_len(struct net_device *dev, u32 preset) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 10228c2ecf20Sopenharmony_ci int regdump_len = 0; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci regdump_len = __bnx2x_get_preset_regs_len(bp, preset); 10258c2ecf20Sopenharmony_ci regdump_len *= 4; 10268c2ecf20Sopenharmony_ci regdump_len += sizeof(struct dump_header); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci return regdump_len; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int bnx2x_set_dump(struct net_device *dev, struct ethtool_dump *val) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* Use the ethtool_dump "flag" field as the dump preset index */ 10368c2ecf20Sopenharmony_ci if (val->flag < 1 || val->flag > DUMP_MAX_PRESETS) 10378c2ecf20Sopenharmony_ci return -EINVAL; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci bp->dump_preset_idx = val->flag; 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic int bnx2x_get_dump_flag(struct net_device *dev, 10448c2ecf20Sopenharmony_ci struct ethtool_dump *dump) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci dump->version = BNX2X_DUMP_VERSION; 10498c2ecf20Sopenharmony_ci dump->flag = bp->dump_preset_idx; 10508c2ecf20Sopenharmony_ci /* Calculate the requested preset idx length */ 10518c2ecf20Sopenharmony_ci dump->len = bnx2x_get_preset_regs_len(dev, bp->dump_preset_idx); 10528c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Get dump preset %d length=%d\n", 10538c2ecf20Sopenharmony_ci bp->dump_preset_idx, dump->len); 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic int bnx2x_get_dump_data(struct net_device *dev, 10588c2ecf20Sopenharmony_ci struct ethtool_dump *dump, 10598c2ecf20Sopenharmony_ci void *buffer) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci u32 *p = buffer; 10628c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 10638c2ecf20Sopenharmony_ci struct dump_header dump_hdr = {0}; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Disable parity attentions as long as following dump may 10668c2ecf20Sopenharmony_ci * cause false alarms by reading never written registers. We 10678c2ecf20Sopenharmony_ci * will re-enable parity attentions right after the dump. 10688c2ecf20Sopenharmony_ci */ 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci bnx2x_disable_blocks_parity(bp); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci dump_hdr.header_size = (sizeof(struct dump_header) / 4) - 1; 10738c2ecf20Sopenharmony_ci dump_hdr.preset = bp->dump_preset_idx; 10748c2ecf20Sopenharmony_ci dump_hdr.version = BNX2X_DUMP_VERSION; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Get dump data of preset %d\n", dump_hdr.preset); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* dump_meta_data presents OR of CHIP and PATH. */ 10798c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) { 10808c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E1; 10818c2ecf20Sopenharmony_ci } else if (CHIP_IS_E1H(bp)) { 10828c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E1H; 10838c2ecf20Sopenharmony_ci } else if (CHIP_IS_E2(bp)) { 10848c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E2 | 10858c2ecf20Sopenharmony_ci (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0); 10868c2ecf20Sopenharmony_ci } else if (CHIP_IS_E3A0(bp)) { 10878c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E3A0 | 10888c2ecf20Sopenharmony_ci (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0); 10898c2ecf20Sopenharmony_ci } else if (CHIP_IS_E3B0(bp)) { 10908c2ecf20Sopenharmony_ci dump_hdr.dump_meta_data = DUMP_CHIP_E3B0 | 10918c2ecf20Sopenharmony_ci (BP_PATH(bp) ? DUMP_PATH_1 : DUMP_PATH_0); 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci memcpy(p, &dump_hdr, sizeof(struct dump_header)); 10958c2ecf20Sopenharmony_ci p += dump_hdr.header_size + 1; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Actually read the registers */ 10988c2ecf20Sopenharmony_ci __bnx2x_get_preset_regs(bp, p, dump_hdr.preset); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Re-enable parity attentions */ 11018c2ecf20Sopenharmony_ci bnx2x_clear_blocks_parity(bp); 11028c2ecf20Sopenharmony_ci bnx2x_enable_blocks_parity(bp); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci return 0; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void bnx2x_get_drvinfo(struct net_device *dev, 11088c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 11118c2ecf20Sopenharmony_ci char version[ETHTOOL_FWVERS_LEN]; 11128c2ecf20Sopenharmony_ci int ext_dev_info_offset; 11138c2ecf20Sopenharmony_ci u32 mbi; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (SHMEM2_HAS(bp, extended_dev_info_shared_addr)) { 11188c2ecf20Sopenharmony_ci ext_dev_info_offset = SHMEM2_RD(bp, 11198c2ecf20Sopenharmony_ci extended_dev_info_shared_addr); 11208c2ecf20Sopenharmony_ci mbi = REG_RD(bp, ext_dev_info_offset + 11218c2ecf20Sopenharmony_ci offsetof(struct extended_dev_info_shared_cfg, 11228c2ecf20Sopenharmony_ci mbi_version)); 11238c2ecf20Sopenharmony_ci if (mbi) { 11248c2ecf20Sopenharmony_ci memset(version, 0, sizeof(version)); 11258c2ecf20Sopenharmony_ci snprintf(version, ETHTOOL_FWVERS_LEN, "mbi %d.%d.%d ", 11268c2ecf20Sopenharmony_ci (mbi & 0xff000000) >> 24, 11278c2ecf20Sopenharmony_ci (mbi & 0x00ff0000) >> 16, 11288c2ecf20Sopenharmony_ci (mbi & 0x0000ff00) >> 8); 11298c2ecf20Sopenharmony_ci strlcpy(info->fw_version, version, 11308c2ecf20Sopenharmony_ci sizeof(info->fw_version)); 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci memset(version, 0, sizeof(version)); 11358c2ecf20Sopenharmony_ci bnx2x_fill_fw_str(bp, version, ETHTOOL_FWVERS_LEN); 11368c2ecf20Sopenharmony_ci strlcat(info->fw_version, version, sizeof(info->fw_version)); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (bp->flags & NO_WOL_FLAG) { 11468c2ecf20Sopenharmony_ci wol->supported = 0; 11478c2ecf20Sopenharmony_ci wol->wolopts = 0; 11488c2ecf20Sopenharmony_ci } else { 11498c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 11508c2ecf20Sopenharmony_ci if (bp->wol) 11518c2ecf20Sopenharmony_ci wol->wolopts = WAKE_MAGIC; 11528c2ecf20Sopenharmony_ci else 11538c2ecf20Sopenharmony_ci wol->wolopts = 0; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci memset(&wol->sopass, 0, sizeof(wol->sopass)); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) { 11638c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n"); 11648c2ecf20Sopenharmony_ci return -EINVAL; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) { 11688c2ecf20Sopenharmony_ci if (bp->flags & NO_WOL_FLAG) { 11698c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "WOL not supported\n"); 11708c2ecf20Sopenharmony_ci return -EINVAL; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci bp->wol = 1; 11738c2ecf20Sopenharmony_ci } else 11748c2ecf20Sopenharmony_ci bp->wol = 0; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (SHMEM2_HAS(bp, curr_cfg)) 11778c2ecf20Sopenharmony_ci SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci return 0; 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic u32 bnx2x_get_msglevel(struct net_device *dev) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci return bp->msg_enable; 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic void bnx2x_set_msglevel(struct net_device *dev, u32 level) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (capable(CAP_NET_ADMIN)) { 11948c2ecf20Sopenharmony_ci /* dump MCP trace */ 11958c2ecf20Sopenharmony_ci if (IS_PF(bp) && (level & BNX2X_MSG_MCP)) 11968c2ecf20Sopenharmony_ci bnx2x_fw_dump_lvl(bp, KERN_INFO); 11978c2ecf20Sopenharmony_ci bp->msg_enable = level; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic int bnx2x_nway_reset(struct net_device *dev) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (!bp->port.pmf) 12068c2ecf20Sopenharmony_ci return 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (netif_running(dev)) { 12098c2ecf20Sopenharmony_ci bnx2x_stats_handle(bp, STATS_EVENT_STOP); 12108c2ecf20Sopenharmony_ci bnx2x_force_link_reset(bp); 12118c2ecf20Sopenharmony_ci bnx2x_link_set(bp); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci return 0; 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic u32 bnx2x_get_link(struct net_device *dev) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN)) 12228c2ecf20Sopenharmony_ci return 0; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (IS_VF(bp)) 12258c2ecf20Sopenharmony_ci return !test_bit(BNX2X_LINK_REPORT_LINK_DOWN, 12268c2ecf20Sopenharmony_ci &bp->vf_link_vars.link_report_flags); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return bp->link_vars.link_up; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic int bnx2x_get_eeprom_len(struct net_device *dev) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return bp->common.flash_size; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci/* Per pf misc lock must be acquired before the per port mcp lock. Otherwise, 12398c2ecf20Sopenharmony_ci * had we done things the other way around, if two pfs from the same port would 12408c2ecf20Sopenharmony_ci * attempt to access nvram at the same time, we could run into a scenario such 12418c2ecf20Sopenharmony_ci * as: 12428c2ecf20Sopenharmony_ci * pf A takes the port lock. 12438c2ecf20Sopenharmony_ci * pf B succeeds in taking the same lock since they are from the same port. 12448c2ecf20Sopenharmony_ci * pf A takes the per pf misc lock. Performs eeprom access. 12458c2ecf20Sopenharmony_ci * pf A finishes. Unlocks the per pf misc lock. 12468c2ecf20Sopenharmony_ci * Pf B takes the lock and proceeds to perform it's own access. 12478c2ecf20Sopenharmony_ci * pf A unlocks the per port lock, while pf B is still working (!). 12488c2ecf20Sopenharmony_ci * mcp takes the per port lock and corrupts pf B's access (and/or has it's own 12498c2ecf20Sopenharmony_ci * access corrupted by pf B) 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_cistatic int bnx2x_acquire_nvram_lock(struct bnx2x *bp) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 12548c2ecf20Sopenharmony_ci int count, i; 12558c2ecf20Sopenharmony_ci u32 val; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* acquire HW lock: protect against other PFs in PF Direct Assignment */ 12588c2ecf20Sopenharmony_ci bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_NVRAM); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* adjust timeout for emulation/FPGA */ 12618c2ecf20Sopenharmony_ci count = BNX2X_NVRAM_TIMEOUT_COUNT; 12628c2ecf20Sopenharmony_ci if (CHIP_REV_IS_SLOW(bp)) 12638c2ecf20Sopenharmony_ci count *= 100; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* request access to nvram interface */ 12668c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, 12678c2ecf20Sopenharmony_ci (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port)); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci for (i = 0; i < count*10; i++) { 12708c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); 12718c2ecf20Sopenharmony_ci if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) 12728c2ecf20Sopenharmony_ci break; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci udelay(5); 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) { 12788c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 12798c2ecf20Sopenharmony_ci "cannot get access to nvram interface\n"); 12808c2ecf20Sopenharmony_ci bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_NVRAM); 12818c2ecf20Sopenharmony_ci return -EBUSY; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return 0; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic int bnx2x_release_nvram_lock(struct bnx2x *bp) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 12908c2ecf20Sopenharmony_ci int count, i; 12918c2ecf20Sopenharmony_ci u32 val; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* adjust timeout for emulation/FPGA */ 12948c2ecf20Sopenharmony_ci count = BNX2X_NVRAM_TIMEOUT_COUNT; 12958c2ecf20Sopenharmony_ci if (CHIP_REV_IS_SLOW(bp)) 12968c2ecf20Sopenharmony_ci count *= 100; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* relinquish nvram interface */ 12998c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, 13008c2ecf20Sopenharmony_ci (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port)); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci for (i = 0; i < count*10; i++) { 13038c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); 13048c2ecf20Sopenharmony_ci if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci udelay(5); 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) { 13118c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 13128c2ecf20Sopenharmony_ci "cannot free access to nvram interface\n"); 13138c2ecf20Sopenharmony_ci return -EBUSY; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* release HW lock: protect against other PFs in PF Direct Assignment */ 13178c2ecf20Sopenharmony_ci bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_NVRAM); 13188c2ecf20Sopenharmony_ci return 0; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic void bnx2x_enable_nvram_access(struct bnx2x *bp) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci u32 val; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* enable both bits, even on read */ 13288c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, 13298c2ecf20Sopenharmony_ci (val | MCPR_NVM_ACCESS_ENABLE_EN | 13308c2ecf20Sopenharmony_ci MCPR_NVM_ACCESS_ENABLE_WR_EN)); 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic void bnx2x_disable_nvram_access(struct bnx2x *bp) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci u32 val; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* disable both bits, even after read */ 13408c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, 13418c2ecf20Sopenharmony_ci (val & ~(MCPR_NVM_ACCESS_ENABLE_EN | 13428c2ecf20Sopenharmony_ci MCPR_NVM_ACCESS_ENABLE_WR_EN))); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val, 13468c2ecf20Sopenharmony_ci u32 cmd_flags) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci int count, i, rc; 13498c2ecf20Sopenharmony_ci u32 val; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* build the command word */ 13528c2ecf20Sopenharmony_ci cmd_flags |= MCPR_NVM_COMMAND_DOIT; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /* need to clear DONE bit separately */ 13558c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci /* address of the NVRAM to read from */ 13588c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, 13598c2ecf20Sopenharmony_ci (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci /* issue a read command */ 13628c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* adjust timeout for emulation/FPGA */ 13658c2ecf20Sopenharmony_ci count = BNX2X_NVRAM_TIMEOUT_COUNT; 13668c2ecf20Sopenharmony_ci if (CHIP_REV_IS_SLOW(bp)) 13678c2ecf20Sopenharmony_ci count *= 100; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* wait for completion */ 13708c2ecf20Sopenharmony_ci *ret_val = 0; 13718c2ecf20Sopenharmony_ci rc = -EBUSY; 13728c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 13738c2ecf20Sopenharmony_ci udelay(5); 13748c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (val & MCPR_NVM_COMMAND_DONE) { 13778c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_READ); 13788c2ecf20Sopenharmony_ci /* we read nvram data in cpu order 13798c2ecf20Sopenharmony_ci * but ethtool sees it as an array of bytes 13808c2ecf20Sopenharmony_ci * converting to big-endian will do the work 13818c2ecf20Sopenharmony_ci */ 13828c2ecf20Sopenharmony_ci *ret_val = cpu_to_be32(val); 13838c2ecf20Sopenharmony_ci rc = 0; 13848c2ecf20Sopenharmony_ci break; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci if (rc == -EBUSY) 13888c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 13898c2ecf20Sopenharmony_ci "nvram read timeout expired\n"); 13908c2ecf20Sopenharmony_ci return rc; 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ciint bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, 13948c2ecf20Sopenharmony_ci int buf_size) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci int rc; 13978c2ecf20Sopenharmony_ci u32 cmd_flags; 13988c2ecf20Sopenharmony_ci __be32 val; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { 14018c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 14028c2ecf20Sopenharmony_ci "Invalid parameter: offset 0x%x buf_size 0x%x\n", 14038c2ecf20Sopenharmony_ci offset, buf_size); 14048c2ecf20Sopenharmony_ci return -EINVAL; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (offset + buf_size > bp->common.flash_size) { 14088c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 14098c2ecf20Sopenharmony_ci "Invalid parameter: offset (0x%x) + buf_size (0x%x) > flash_size (0x%x)\n", 14108c2ecf20Sopenharmony_ci offset, buf_size, bp->common.flash_size); 14118c2ecf20Sopenharmony_ci return -EINVAL; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci /* request access to nvram interface */ 14158c2ecf20Sopenharmony_ci rc = bnx2x_acquire_nvram_lock(bp); 14168c2ecf20Sopenharmony_ci if (rc) 14178c2ecf20Sopenharmony_ci return rc; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* enable access to nvram interface */ 14208c2ecf20Sopenharmony_ci bnx2x_enable_nvram_access(bp); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci /* read the first word(s) */ 14238c2ecf20Sopenharmony_ci cmd_flags = MCPR_NVM_COMMAND_FIRST; 14248c2ecf20Sopenharmony_ci while ((buf_size > sizeof(u32)) && (rc == 0)) { 14258c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); 14268c2ecf20Sopenharmony_ci memcpy(ret_buf, &val, 4); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* advance to the next dword */ 14298c2ecf20Sopenharmony_ci offset += sizeof(u32); 14308c2ecf20Sopenharmony_ci ret_buf += sizeof(u32); 14318c2ecf20Sopenharmony_ci buf_size -= sizeof(u32); 14328c2ecf20Sopenharmony_ci cmd_flags = 0; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (rc == 0) { 14368c2ecf20Sopenharmony_ci cmd_flags |= MCPR_NVM_COMMAND_LAST; 14378c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); 14388c2ecf20Sopenharmony_ci memcpy(ret_buf, &val, 4); 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* disable access to nvram interface */ 14428c2ecf20Sopenharmony_ci bnx2x_disable_nvram_access(bp); 14438c2ecf20Sopenharmony_ci bnx2x_release_nvram_lock(bp); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci return rc; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_cistatic int bnx2x_nvram_read32(struct bnx2x *bp, u32 offset, u32 *buf, 14498c2ecf20Sopenharmony_ci int buf_size) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci int rc; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read(bp, offset, (u8 *)buf, buf_size); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if (!rc) { 14568c2ecf20Sopenharmony_ci __be32 *be = (__be32 *)buf; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci while ((buf_size -= 4) >= 0) 14598c2ecf20Sopenharmony_ci *buf++ = be32_to_cpu(*be++); 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci return rc; 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic bool bnx2x_is_nvm_accessible(struct bnx2x *bp) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci int rc = 1; 14688c2ecf20Sopenharmony_ci u16 pm = 0; 14698c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(bp->pdev); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (bp->pdev->pm_cap) 14728c2ecf20Sopenharmony_ci rc = pci_read_config_word(bp->pdev, 14738c2ecf20Sopenharmony_ci bp->pdev->pm_cap + PCI_PM_CTRL, &pm); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if ((rc && !netif_running(dev)) || 14768c2ecf20Sopenharmony_ci (!rc && ((pm & PCI_PM_CTRL_STATE_MASK) != (__force u16)PCI_D0))) 14778c2ecf20Sopenharmony_ci return false; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci return true; 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic int bnx2x_get_eeprom(struct net_device *dev, 14838c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *eebuf) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 14888c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 14898c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 14908c2ecf20Sopenharmony_ci return -EAGAIN; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" 14948c2ecf20Sopenharmony_ci " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", 14958c2ecf20Sopenharmony_ci eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, 14968c2ecf20Sopenharmony_ci eeprom->len, eeprom->len); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci /* parameters already validated in ethtool_get_eeprom */ 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci return bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic int bnx2x_get_module_eeprom(struct net_device *dev, 15048c2ecf20Sopenharmony_ci struct ethtool_eeprom *ee, 15058c2ecf20Sopenharmony_ci u8 *data) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 15088c2ecf20Sopenharmony_ci int rc = -EINVAL, phy_idx; 15098c2ecf20Sopenharmony_ci u8 *user_data = data; 15108c2ecf20Sopenharmony_ci unsigned int start_addr = ee->offset, xfer_size = 0; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 15138c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 15148c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 15158c2ecf20Sopenharmony_ci return -EAGAIN; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci phy_idx = bnx2x_get_cur_phy_idx(bp); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci /* Read A0 section */ 15218c2ecf20Sopenharmony_ci if (start_addr < ETH_MODULE_SFF_8079_LEN) { 15228c2ecf20Sopenharmony_ci /* Limit transfer size to the A0 section boundary */ 15238c2ecf20Sopenharmony_ci if (start_addr + ee->len > ETH_MODULE_SFF_8079_LEN) 15248c2ecf20Sopenharmony_ci xfer_size = ETH_MODULE_SFF_8079_LEN - start_addr; 15258c2ecf20Sopenharmony_ci else 15268c2ecf20Sopenharmony_ci xfer_size = ee->len; 15278c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 15288c2ecf20Sopenharmony_ci rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx], 15298c2ecf20Sopenharmony_ci &bp->link_params, 15308c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, 15318c2ecf20Sopenharmony_ci start_addr, 15328c2ecf20Sopenharmony_ci xfer_size, 15338c2ecf20Sopenharmony_ci user_data); 15348c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 15358c2ecf20Sopenharmony_ci if (rc) { 15368c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Failed reading A0 section\n"); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci return -EINVAL; 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci user_data += xfer_size; 15418c2ecf20Sopenharmony_ci start_addr += xfer_size; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci /* Read A2 section */ 15458c2ecf20Sopenharmony_ci if ((start_addr >= ETH_MODULE_SFF_8079_LEN) && 15468c2ecf20Sopenharmony_ci (start_addr < ETH_MODULE_SFF_8472_LEN)) { 15478c2ecf20Sopenharmony_ci xfer_size = ee->len - xfer_size; 15488c2ecf20Sopenharmony_ci /* Limit transfer size to the A2 section boundary */ 15498c2ecf20Sopenharmony_ci if (start_addr + xfer_size > ETH_MODULE_SFF_8472_LEN) 15508c2ecf20Sopenharmony_ci xfer_size = ETH_MODULE_SFF_8472_LEN - start_addr; 15518c2ecf20Sopenharmony_ci start_addr -= ETH_MODULE_SFF_8079_LEN; 15528c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 15538c2ecf20Sopenharmony_ci rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx], 15548c2ecf20Sopenharmony_ci &bp->link_params, 15558c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A2, 15568c2ecf20Sopenharmony_ci start_addr, 15578c2ecf20Sopenharmony_ci xfer_size, 15588c2ecf20Sopenharmony_ci user_data); 15598c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 15608c2ecf20Sopenharmony_ci if (rc) { 15618c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Failed reading A2 section\n"); 15628c2ecf20Sopenharmony_ci return -EINVAL; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci return rc; 15668c2ecf20Sopenharmony_ci} 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_cistatic int bnx2x_get_module_info(struct net_device *dev, 15698c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 15728c2ecf20Sopenharmony_ci int phy_idx, rc; 15738c2ecf20Sopenharmony_ci u8 sff8472_comp, diag_type; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 15768c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 15778c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 15788c2ecf20Sopenharmony_ci return -EAGAIN; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci phy_idx = bnx2x_get_cur_phy_idx(bp); 15818c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 15828c2ecf20Sopenharmony_ci rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx], 15838c2ecf20Sopenharmony_ci &bp->link_params, 15848c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, 15858c2ecf20Sopenharmony_ci SFP_EEPROM_SFF_8472_COMP_ADDR, 15868c2ecf20Sopenharmony_ci SFP_EEPROM_SFF_8472_COMP_SIZE, 15878c2ecf20Sopenharmony_ci &sff8472_comp); 15888c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 15898c2ecf20Sopenharmony_ci if (rc) { 15908c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Failed reading SFF-8472 comp field\n"); 15918c2ecf20Sopenharmony_ci return -EINVAL; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 15958c2ecf20Sopenharmony_ci rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx], 15968c2ecf20Sopenharmony_ci &bp->link_params, 15978c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, 15988c2ecf20Sopenharmony_ci SFP_EEPROM_DIAG_TYPE_ADDR, 15998c2ecf20Sopenharmony_ci SFP_EEPROM_DIAG_TYPE_SIZE, 16008c2ecf20Sopenharmony_ci &diag_type); 16018c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 16028c2ecf20Sopenharmony_ci if (rc) { 16038c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Failed reading Diag Type field\n"); 16048c2ecf20Sopenharmony_ci return -EINVAL; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (!sff8472_comp || 16088c2ecf20Sopenharmony_ci (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ) || 16098c2ecf20Sopenharmony_ci !(diag_type & SFP_EEPROM_DDM_IMPLEMENTED)) { 16108c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 16118c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 16128c2ecf20Sopenharmony_ci } else { 16138c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 16148c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci return 0; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val, 16208c2ecf20Sopenharmony_ci u32 cmd_flags) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci int count, i, rc; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* build the command word */ 16258c2ecf20Sopenharmony_ci cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* need to clear DONE bit separately */ 16288c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* write the data */ 16318c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci /* address of the NVRAM to write to */ 16348c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, 16358c2ecf20Sopenharmony_ci (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* issue the write command */ 16388c2ecf20Sopenharmony_ci REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci /* adjust timeout for emulation/FPGA */ 16418c2ecf20Sopenharmony_ci count = BNX2X_NVRAM_TIMEOUT_COUNT; 16428c2ecf20Sopenharmony_ci if (CHIP_REV_IS_SLOW(bp)) 16438c2ecf20Sopenharmony_ci count *= 100; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* wait for completion */ 16468c2ecf20Sopenharmony_ci rc = -EBUSY; 16478c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 16488c2ecf20Sopenharmony_ci udelay(5); 16498c2ecf20Sopenharmony_ci val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); 16508c2ecf20Sopenharmony_ci if (val & MCPR_NVM_COMMAND_DONE) { 16518c2ecf20Sopenharmony_ci rc = 0; 16528c2ecf20Sopenharmony_ci break; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (rc == -EBUSY) 16578c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 16588c2ecf20Sopenharmony_ci "nvram write timeout expired\n"); 16598c2ecf20Sopenharmony_ci return rc; 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci#define BYTE_OFFSET(offset) (8 * (offset & 0x03)) 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_cistatic int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, 16658c2ecf20Sopenharmony_ci int buf_size) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci int rc; 16688c2ecf20Sopenharmony_ci u32 cmd_flags, align_offset, val; 16698c2ecf20Sopenharmony_ci __be32 val_be; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (offset + buf_size > bp->common.flash_size) { 16728c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 16738c2ecf20Sopenharmony_ci "Invalid parameter: offset (0x%x) + buf_size (0x%x) > flash_size (0x%x)\n", 16748c2ecf20Sopenharmony_ci offset, buf_size, bp->common.flash_size); 16758c2ecf20Sopenharmony_ci return -EINVAL; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* request access to nvram interface */ 16798c2ecf20Sopenharmony_ci rc = bnx2x_acquire_nvram_lock(bp); 16808c2ecf20Sopenharmony_ci if (rc) 16818c2ecf20Sopenharmony_ci return rc; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci /* enable access to nvram interface */ 16848c2ecf20Sopenharmony_ci bnx2x_enable_nvram_access(bp); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST); 16878c2ecf20Sopenharmony_ci align_offset = (offset & ~0x03); 16888c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read_dword(bp, align_offset, &val_be, cmd_flags); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (rc == 0) { 16918c2ecf20Sopenharmony_ci /* nvram data is returned as an array of bytes 16928c2ecf20Sopenharmony_ci * convert it back to cpu order 16938c2ecf20Sopenharmony_ci */ 16948c2ecf20Sopenharmony_ci val = be32_to_cpu(val_be); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci val &= ~le32_to_cpu((__force __le32) 16978c2ecf20Sopenharmony_ci (0xff << BYTE_OFFSET(offset))); 16988c2ecf20Sopenharmony_ci val |= le32_to_cpu((__force __le32) 16998c2ecf20Sopenharmony_ci (*data_buf << BYTE_OFFSET(offset))); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci rc = bnx2x_nvram_write_dword(bp, align_offset, val, 17028c2ecf20Sopenharmony_ci cmd_flags); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* disable access to nvram interface */ 17068c2ecf20Sopenharmony_ci bnx2x_disable_nvram_access(bp); 17078c2ecf20Sopenharmony_ci bnx2x_release_nvram_lock(bp); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci return rc; 17108c2ecf20Sopenharmony_ci} 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_cistatic int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, 17138c2ecf20Sopenharmony_ci int buf_size) 17148c2ecf20Sopenharmony_ci{ 17158c2ecf20Sopenharmony_ci int rc; 17168c2ecf20Sopenharmony_ci u32 cmd_flags; 17178c2ecf20Sopenharmony_ci u32 val; 17188c2ecf20Sopenharmony_ci u32 written_so_far; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci if (buf_size == 1) /* ethtool */ 17218c2ecf20Sopenharmony_ci return bnx2x_nvram_write1(bp, offset, data_buf, buf_size); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { 17248c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 17258c2ecf20Sopenharmony_ci "Invalid parameter: offset 0x%x buf_size 0x%x\n", 17268c2ecf20Sopenharmony_ci offset, buf_size); 17278c2ecf20Sopenharmony_ci return -EINVAL; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (offset + buf_size > bp->common.flash_size) { 17318c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 17328c2ecf20Sopenharmony_ci "Invalid parameter: offset (0x%x) + buf_size (0x%x) > flash_size (0x%x)\n", 17338c2ecf20Sopenharmony_ci offset, buf_size, bp->common.flash_size); 17348c2ecf20Sopenharmony_ci return -EINVAL; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci /* request access to nvram interface */ 17388c2ecf20Sopenharmony_ci rc = bnx2x_acquire_nvram_lock(bp); 17398c2ecf20Sopenharmony_ci if (rc) 17408c2ecf20Sopenharmony_ci return rc; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci /* enable access to nvram interface */ 17438c2ecf20Sopenharmony_ci bnx2x_enable_nvram_access(bp); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci written_so_far = 0; 17468c2ecf20Sopenharmony_ci cmd_flags = MCPR_NVM_COMMAND_FIRST; 17478c2ecf20Sopenharmony_ci while ((written_so_far < buf_size) && (rc == 0)) { 17488c2ecf20Sopenharmony_ci if (written_so_far == (buf_size - sizeof(u32))) 17498c2ecf20Sopenharmony_ci cmd_flags |= MCPR_NVM_COMMAND_LAST; 17508c2ecf20Sopenharmony_ci else if (((offset + 4) % BNX2X_NVRAM_PAGE_SIZE) == 0) 17518c2ecf20Sopenharmony_ci cmd_flags |= MCPR_NVM_COMMAND_LAST; 17528c2ecf20Sopenharmony_ci else if ((offset % BNX2X_NVRAM_PAGE_SIZE) == 0) 17538c2ecf20Sopenharmony_ci cmd_flags |= MCPR_NVM_COMMAND_FIRST; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci memcpy(&val, data_buf, 4); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci /* Notice unlike bnx2x_nvram_read_dword() this will not 17588c2ecf20Sopenharmony_ci * change val using be32_to_cpu(), which causes data to flip 17598c2ecf20Sopenharmony_ci * if the eeprom is read and then written back. This is due 17608c2ecf20Sopenharmony_ci * to tools utilizing this functionality that would break 17618c2ecf20Sopenharmony_ci * if this would be resolved. 17628c2ecf20Sopenharmony_ci */ 17638c2ecf20Sopenharmony_ci rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* advance to the next dword */ 17668c2ecf20Sopenharmony_ci offset += sizeof(u32); 17678c2ecf20Sopenharmony_ci data_buf += sizeof(u32); 17688c2ecf20Sopenharmony_ci written_so_far += sizeof(u32); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci /* At end of each 4Kb page, release nvram lock to allow MFW 17718c2ecf20Sopenharmony_ci * chance to take it for its own use. 17728c2ecf20Sopenharmony_ci */ 17738c2ecf20Sopenharmony_ci if ((cmd_flags & MCPR_NVM_COMMAND_LAST) && 17748c2ecf20Sopenharmony_ci (written_so_far < buf_size)) { 17758c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 17768c2ecf20Sopenharmony_ci "Releasing NVM lock after offset 0x%x\n", 17778c2ecf20Sopenharmony_ci (u32)(offset - sizeof(u32))); 17788c2ecf20Sopenharmony_ci bnx2x_release_nvram_lock(bp); 17798c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 17808c2ecf20Sopenharmony_ci rc = bnx2x_acquire_nvram_lock(bp); 17818c2ecf20Sopenharmony_ci if (rc) 17828c2ecf20Sopenharmony_ci return rc; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci cmd_flags = 0; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* disable access to nvram interface */ 17898c2ecf20Sopenharmony_ci bnx2x_disable_nvram_access(bp); 17908c2ecf20Sopenharmony_ci bnx2x_release_nvram_lock(bp); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci return rc; 17938c2ecf20Sopenharmony_ci} 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cistatic int bnx2x_set_eeprom(struct net_device *dev, 17968c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *eebuf) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 17998c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 18008c2ecf20Sopenharmony_ci int rc = 0; 18018c2ecf20Sopenharmony_ci u32 ext_phy_config; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 18048c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 18058c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 18068c2ecf20Sopenharmony_ci return -EAGAIN; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" 18108c2ecf20Sopenharmony_ci " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", 18118c2ecf20Sopenharmony_ci eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, 18128c2ecf20Sopenharmony_ci eeprom->len, eeprom->len); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci /* parameters already validated in ethtool_set_eeprom */ 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* PHY eeprom can be accessed only by the PMF */ 18178c2ecf20Sopenharmony_ci if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) && 18188c2ecf20Sopenharmony_ci !bp->port.pmf) { 18198c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 18208c2ecf20Sopenharmony_ci "wrong magic or interface is not pmf\n"); 18218c2ecf20Sopenharmony_ci return -EINVAL; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci ext_phy_config = 18258c2ecf20Sopenharmony_ci SHMEM_RD(bp, 18268c2ecf20Sopenharmony_ci dev_info.port_hw_config[port].external_phy_config); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (eeprom->magic == 0x50485950) { 18298c2ecf20Sopenharmony_ci /* 'PHYP' (0x50485950): prepare phy for FW upgrade */ 18308c2ecf20Sopenharmony_ci bnx2x_stats_handle(bp, STATS_EVENT_STOP); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 18338c2ecf20Sopenharmony_ci rc |= bnx2x_link_reset(&bp->link_params, 18348c2ecf20Sopenharmony_ci &bp->link_vars, 0); 18358c2ecf20Sopenharmony_ci if (XGXS_EXT_PHY_TYPE(ext_phy_config) == 18368c2ecf20Sopenharmony_ci PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) 18378c2ecf20Sopenharmony_ci bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, 18388c2ecf20Sopenharmony_ci MISC_REGISTERS_GPIO_HIGH, port); 18398c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 18408c2ecf20Sopenharmony_ci bnx2x_link_report(bp); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci } else if (eeprom->magic == 0x50485952) { 18438c2ecf20Sopenharmony_ci /* 'PHYR' (0x50485952): re-init link after FW upgrade */ 18448c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) { 18458c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 18468c2ecf20Sopenharmony_ci rc |= bnx2x_link_reset(&bp->link_params, 18478c2ecf20Sopenharmony_ci &bp->link_vars, 1); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci rc |= bnx2x_phy_init(&bp->link_params, 18508c2ecf20Sopenharmony_ci &bp->link_vars); 18518c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 18528c2ecf20Sopenharmony_ci bnx2x_calc_fc_adv(bp); 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci } else if (eeprom->magic == 0x53985943) { 18558c2ecf20Sopenharmony_ci /* 'PHYC' (0x53985943): PHY FW upgrade completed */ 18568c2ecf20Sopenharmony_ci if (XGXS_EXT_PHY_TYPE(ext_phy_config) == 18578c2ecf20Sopenharmony_ci PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) { 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci /* DSP Remove Download Mode */ 18608c2ecf20Sopenharmony_ci bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, 18618c2ecf20Sopenharmony_ci MISC_REGISTERS_GPIO_LOW, port); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci bnx2x_sfx7101_sp_sw_reset(bp, 18668c2ecf20Sopenharmony_ci &bp->link_params.phy[EXT_PHY1]); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci /* wait 0.5 sec to allow it to run */ 18698c2ecf20Sopenharmony_ci msleep(500); 18708c2ecf20Sopenharmony_ci bnx2x_ext_phy_hw_reset(bp, port); 18718c2ecf20Sopenharmony_ci msleep(500); 18728c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci } else 18758c2ecf20Sopenharmony_ci rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci return rc; 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_cistatic int bnx2x_get_coalesce(struct net_device *dev, 18818c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci memset(coal, 0, sizeof(struct ethtool_coalesce)); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs = bp->rx_ticks; 18888c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs = bp->tx_ticks; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic int bnx2x_set_coalesce(struct net_device *dev, 18948c2ecf20Sopenharmony_ci struct ethtool_coalesce *coal) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci bp->rx_ticks = (u16)coal->rx_coalesce_usecs; 18998c2ecf20Sopenharmony_ci if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT) 19008c2ecf20Sopenharmony_ci bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci bp->tx_ticks = (u16)coal->tx_coalesce_usecs; 19038c2ecf20Sopenharmony_ci if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT) 19048c2ecf20Sopenharmony_ci bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (netif_running(dev)) 19078c2ecf20Sopenharmony_ci bnx2x_update_coalesce(bp); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci return 0; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic void bnx2x_get_ringparam(struct net_device *dev, 19138c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 19148c2ecf20Sopenharmony_ci{ 19158c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci ering->rx_max_pending = MAX_RX_AVAIL; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* If size isn't already set, we give an estimation of the number 19208c2ecf20Sopenharmony_ci * of buffers we'll have. We're neglecting some possible conditions 19218c2ecf20Sopenharmony_ci * [we couldn't know for certain at this point if number of queues 19228c2ecf20Sopenharmony_ci * might shrink] but the number would be correct for the likely 19238c2ecf20Sopenharmony_ci * scenario. 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_ci if (bp->rx_ring_size) 19268c2ecf20Sopenharmony_ci ering->rx_pending = bp->rx_ring_size; 19278c2ecf20Sopenharmony_ci else if (BNX2X_NUM_RX_QUEUES(bp)) 19288c2ecf20Sopenharmony_ci ering->rx_pending = MAX_RX_AVAIL / BNX2X_NUM_RX_QUEUES(bp); 19298c2ecf20Sopenharmony_ci else 19308c2ecf20Sopenharmony_ci ering->rx_pending = MAX_RX_AVAIL; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci ering->tx_max_pending = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL; 19338c2ecf20Sopenharmony_ci ering->tx_pending = bp->tx_ring_size; 19348c2ecf20Sopenharmony_ci} 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_cistatic int bnx2x_set_ringparam(struct net_device *dev, 19378c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 19428c2ecf20Sopenharmony_ci "set ring params command parameters: rx_pending = %d, tx_pending = %d\n", 19438c2ecf20Sopenharmony_ci ering->rx_pending, ering->tx_pending); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci if (pci_num_vf(bp->pdev)) { 19468c2ecf20Sopenharmony_ci DP(BNX2X_MSG_IOV, 19478c2ecf20Sopenharmony_ci "VFs are enabled, can not change ring parameters\n"); 19488c2ecf20Sopenharmony_ci return -EPERM; 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (bp->recovery_state != BNX2X_RECOVERY_DONE) { 19528c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 19538c2ecf20Sopenharmony_ci "Handling parity error recovery. Try again later\n"); 19548c2ecf20Sopenharmony_ci return -EAGAIN; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if ((ering->rx_pending > MAX_RX_AVAIL) || 19588c2ecf20Sopenharmony_ci (ering->rx_pending < (bp->disable_tpa ? MIN_RX_SIZE_NONTPA : 19598c2ecf20Sopenharmony_ci MIN_RX_SIZE_TPA)) || 19608c2ecf20Sopenharmony_ci (ering->tx_pending > (IS_MF_STORAGE_ONLY(bp) ? 0 : MAX_TX_AVAIL)) || 19618c2ecf20Sopenharmony_ci (ering->tx_pending <= MAX_SKB_FRAGS + 4)) { 19628c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n"); 19638c2ecf20Sopenharmony_ci return -EINVAL; 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci bp->rx_ring_size = ering->rx_pending; 19678c2ecf20Sopenharmony_ci bp->tx_ring_size = ering->tx_pending; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci return bnx2x_reload_if_running(dev); 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic void bnx2x_get_pauseparam(struct net_device *dev, 19738c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 19768c2ecf20Sopenharmony_ci int cfg_idx = bnx2x_get_link_cfg_idx(bp); 19778c2ecf20Sopenharmony_ci int cfg_reg; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci epause->autoneg = (bp->link_params.req_flow_ctrl[cfg_idx] == 19808c2ecf20Sopenharmony_ci BNX2X_FLOW_CTRL_AUTO); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if (!epause->autoneg) 19838c2ecf20Sopenharmony_ci cfg_reg = bp->link_params.req_flow_ctrl[cfg_idx]; 19848c2ecf20Sopenharmony_ci else 19858c2ecf20Sopenharmony_ci cfg_reg = bp->link_params.req_fc_auto_adv; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci epause->rx_pause = ((cfg_reg & BNX2X_FLOW_CTRL_RX) == 19888c2ecf20Sopenharmony_ci BNX2X_FLOW_CTRL_RX); 19898c2ecf20Sopenharmony_ci epause->tx_pause = ((cfg_reg & BNX2X_FLOW_CTRL_TX) == 19908c2ecf20Sopenharmony_ci BNX2X_FLOW_CTRL_TX); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "ethtool_pauseparam: cmd %d\n" 19938c2ecf20Sopenharmony_ci " autoneg %d rx_pause %d tx_pause %d\n", 19948c2ecf20Sopenharmony_ci epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); 19958c2ecf20Sopenharmony_ci} 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_cistatic int bnx2x_set_pauseparam(struct net_device *dev, 19988c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 19998c2ecf20Sopenharmony_ci{ 20008c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 20018c2ecf20Sopenharmony_ci u32 cfg_idx = bnx2x_get_link_cfg_idx(bp); 20028c2ecf20Sopenharmony_ci if (IS_MF(bp)) 20038c2ecf20Sopenharmony_ci return 0; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "ethtool_pauseparam: cmd %d\n" 20068c2ecf20Sopenharmony_ci " autoneg %d rx_pause %d tx_pause %d\n", 20078c2ecf20Sopenharmony_ci epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (epause->rx_pause) 20128c2ecf20Sopenharmony_ci bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_RX; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (epause->tx_pause) 20158c2ecf20Sopenharmony_ci bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_TX; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (bp->link_params.req_flow_ctrl[cfg_idx] == BNX2X_FLOW_CTRL_AUTO) 20188c2ecf20Sopenharmony_ci bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_NONE; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (epause->autoneg) { 20218c2ecf20Sopenharmony_ci if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) { 20228c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "autoneg not supported\n"); 20238c2ecf20Sopenharmony_ci return -EINVAL; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) { 20278c2ecf20Sopenharmony_ci bp->link_params.req_flow_ctrl[cfg_idx] = 20288c2ecf20Sopenharmony_ci BNX2X_FLOW_CTRL_AUTO; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci bp->link_params.req_fc_auto_adv = 0; 20318c2ecf20Sopenharmony_ci if (epause->rx_pause) 20328c2ecf20Sopenharmony_ci bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_RX; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci if (epause->tx_pause) 20358c2ecf20Sopenharmony_ci bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_TX; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (!bp->link_params.req_fc_auto_adv) 20388c2ecf20Sopenharmony_ci bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_NONE; 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 20428c2ecf20Sopenharmony_ci "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl[cfg_idx]); 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if (netif_running(dev)) { 20458c2ecf20Sopenharmony_ci bnx2x_stats_handle(bp, STATS_EVENT_STOP); 20468c2ecf20Sopenharmony_ci bnx2x_force_link_reset(bp); 20478c2ecf20Sopenharmony_ci bnx2x_link_set(bp); 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci return 0; 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic const char bnx2x_tests_str_arr[BNX2X_NUM_TESTS_SF][ETH_GSTRING_LEN] = { 20548c2ecf20Sopenharmony_ci "register_test (offline) ", 20558c2ecf20Sopenharmony_ci "memory_test (offline) ", 20568c2ecf20Sopenharmony_ci "int_loopback_test (offline)", 20578c2ecf20Sopenharmony_ci "ext_loopback_test (offline)", 20588c2ecf20Sopenharmony_ci "nvram_test (online) ", 20598c2ecf20Sopenharmony_ci "interrupt_test (online) ", 20608c2ecf20Sopenharmony_ci "link_test (online) " 20618c2ecf20Sopenharmony_ci}; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_cienum { 20648c2ecf20Sopenharmony_ci BNX2X_PRI_FLAG_ISCSI, 20658c2ecf20Sopenharmony_ci BNX2X_PRI_FLAG_FCOE, 20668c2ecf20Sopenharmony_ci BNX2X_PRI_FLAG_STORAGE, 20678c2ecf20Sopenharmony_ci BNX2X_PRI_FLAG_LEN, 20688c2ecf20Sopenharmony_ci}; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_cistatic const char bnx2x_private_arr[BNX2X_PRI_FLAG_LEN][ETH_GSTRING_LEN] = { 20718c2ecf20Sopenharmony_ci "iSCSI offload support", 20728c2ecf20Sopenharmony_ci "FCoE offload support", 20738c2ecf20Sopenharmony_ci "Storage only interface" 20748c2ecf20Sopenharmony_ci}; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic u32 bnx2x_eee_to_adv(u32 eee_adv) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci u32 modes = 0; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (eee_adv & SHMEM_EEE_100M_ADV) 20818c2ecf20Sopenharmony_ci modes |= ADVERTISED_100baseT_Full; 20828c2ecf20Sopenharmony_ci if (eee_adv & SHMEM_EEE_1G_ADV) 20838c2ecf20Sopenharmony_ci modes |= ADVERTISED_1000baseT_Full; 20848c2ecf20Sopenharmony_ci if (eee_adv & SHMEM_EEE_10G_ADV) 20858c2ecf20Sopenharmony_ci modes |= ADVERTISED_10000baseT_Full; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci return modes; 20888c2ecf20Sopenharmony_ci} 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic u32 bnx2x_adv_to_eee(u32 modes, u32 shift) 20918c2ecf20Sopenharmony_ci{ 20928c2ecf20Sopenharmony_ci u32 eee_adv = 0; 20938c2ecf20Sopenharmony_ci if (modes & ADVERTISED_100baseT_Full) 20948c2ecf20Sopenharmony_ci eee_adv |= SHMEM_EEE_100M_ADV; 20958c2ecf20Sopenharmony_ci if (modes & ADVERTISED_1000baseT_Full) 20968c2ecf20Sopenharmony_ci eee_adv |= SHMEM_EEE_1G_ADV; 20978c2ecf20Sopenharmony_ci if (modes & ADVERTISED_10000baseT_Full) 20988c2ecf20Sopenharmony_ci eee_adv |= SHMEM_EEE_10G_ADV; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci return eee_adv << shift; 21018c2ecf20Sopenharmony_ci} 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_cistatic int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata) 21048c2ecf20Sopenharmony_ci{ 21058c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 21068c2ecf20Sopenharmony_ci u32 eee_cfg; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci if (!SHMEM2_HAS(bp, eee_status[BP_PORT(bp)])) { 21098c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "BC Version does not support EEE\n"); 21108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci eee_cfg = bp->link_vars.eee_status; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci edata->supported = 21168c2ecf20Sopenharmony_ci bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_SUPPORTED_MASK) >> 21178c2ecf20Sopenharmony_ci SHMEM_EEE_SUPPORTED_SHIFT); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci edata->advertised = 21208c2ecf20Sopenharmony_ci bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_ADV_STATUS_MASK) >> 21218c2ecf20Sopenharmony_ci SHMEM_EEE_ADV_STATUS_SHIFT); 21228c2ecf20Sopenharmony_ci edata->lp_advertised = 21238c2ecf20Sopenharmony_ci bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_LP_ADV_STATUS_MASK) >> 21248c2ecf20Sopenharmony_ci SHMEM_EEE_LP_ADV_STATUS_SHIFT); 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci /* SHMEM value is in 16u units --> Convert to 1u units. */ 21278c2ecf20Sopenharmony_ci edata->tx_lpi_timer = (eee_cfg & SHMEM_EEE_TIMER_MASK) << 4; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci edata->eee_enabled = (eee_cfg & SHMEM_EEE_REQUESTED_BIT) ? 1 : 0; 21308c2ecf20Sopenharmony_ci edata->eee_active = (eee_cfg & SHMEM_EEE_ACTIVE_BIT) ? 1 : 0; 21318c2ecf20Sopenharmony_ci edata->tx_lpi_enabled = (eee_cfg & SHMEM_EEE_LPI_REQUESTED_BIT) ? 1 : 0; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci return 0; 21348c2ecf20Sopenharmony_ci} 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_cistatic int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata) 21378c2ecf20Sopenharmony_ci{ 21388c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 21398c2ecf20Sopenharmony_ci u32 eee_cfg; 21408c2ecf20Sopenharmony_ci u32 advertised; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci if (IS_MF(bp)) 21438c2ecf20Sopenharmony_ci return 0; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci if (!SHMEM2_HAS(bp, eee_status[BP_PORT(bp)])) { 21468c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "BC Version does not support EEE\n"); 21478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21488c2ecf20Sopenharmony_ci } 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci eee_cfg = bp->link_vars.eee_status; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (!(eee_cfg & SHMEM_EEE_SUPPORTED_MASK)) { 21538c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Board does not support EEE!\n"); 21548c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci advertised = bnx2x_adv_to_eee(edata->advertised, 21588c2ecf20Sopenharmony_ci SHMEM_EEE_ADV_STATUS_SHIFT); 21598c2ecf20Sopenharmony_ci if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) { 21608c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 21618c2ecf20Sopenharmony_ci "Direct manipulation of EEE advertisement is not supported\n"); 21628c2ecf20Sopenharmony_ci return -EINVAL; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (edata->tx_lpi_timer > EEE_MODE_TIMER_MASK) { 21668c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 21678c2ecf20Sopenharmony_ci "Maximal Tx Lpi timer supported is %x(u)\n", 21688c2ecf20Sopenharmony_ci EEE_MODE_TIMER_MASK); 21698c2ecf20Sopenharmony_ci return -EINVAL; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci if (edata->tx_lpi_enabled && 21728c2ecf20Sopenharmony_ci (edata->tx_lpi_timer < EEE_MODE_NVRAM_AGGRESSIVE_TIME)) { 21738c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 21748c2ecf20Sopenharmony_ci "Minimal Tx Lpi timer supported is %d(u)\n", 21758c2ecf20Sopenharmony_ci EEE_MODE_NVRAM_AGGRESSIVE_TIME); 21768c2ecf20Sopenharmony_ci return -EINVAL; 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci /* All is well; Apply changes*/ 21808c2ecf20Sopenharmony_ci if (edata->eee_enabled) 21818c2ecf20Sopenharmony_ci bp->link_params.eee_mode |= EEE_MODE_ADV_LPI; 21828c2ecf20Sopenharmony_ci else 21838c2ecf20Sopenharmony_ci bp->link_params.eee_mode &= ~EEE_MODE_ADV_LPI; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci if (edata->tx_lpi_enabled) 21868c2ecf20Sopenharmony_ci bp->link_params.eee_mode |= EEE_MODE_ENABLE_LPI; 21878c2ecf20Sopenharmony_ci else 21888c2ecf20Sopenharmony_ci bp->link_params.eee_mode &= ~EEE_MODE_ENABLE_LPI; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci bp->link_params.eee_mode &= ~EEE_MODE_TIMER_MASK; 21918c2ecf20Sopenharmony_ci bp->link_params.eee_mode |= (edata->tx_lpi_timer & 21928c2ecf20Sopenharmony_ci EEE_MODE_TIMER_MASK) | 21938c2ecf20Sopenharmony_ci EEE_MODE_OVERRIDE_NVRAM | 21948c2ecf20Sopenharmony_ci EEE_MODE_OUTPUT_TIME; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci /* Restart link to propagate changes */ 21978c2ecf20Sopenharmony_ci if (netif_running(dev)) { 21988c2ecf20Sopenharmony_ci bnx2x_stats_handle(bp, STATS_EVENT_STOP); 21998c2ecf20Sopenharmony_ci bnx2x_force_link_reset(bp); 22008c2ecf20Sopenharmony_ci bnx2x_link_set(bp); 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci return 0; 22048c2ecf20Sopenharmony_ci} 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_cienum { 22078c2ecf20Sopenharmony_ci BNX2X_CHIP_E1_OFST = 0, 22088c2ecf20Sopenharmony_ci BNX2X_CHIP_E1H_OFST, 22098c2ecf20Sopenharmony_ci BNX2X_CHIP_E2_OFST, 22108c2ecf20Sopenharmony_ci BNX2X_CHIP_E3_OFST, 22118c2ecf20Sopenharmony_ci BNX2X_CHIP_E3B0_OFST, 22128c2ecf20Sopenharmony_ci BNX2X_CHIP_MAX_OFST 22138c2ecf20Sopenharmony_ci}; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_E1 (1 << BNX2X_CHIP_E1_OFST) 22168c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_E1H (1 << BNX2X_CHIP_E1H_OFST) 22178c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_E2 (1 << BNX2X_CHIP_E2_OFST) 22188c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_E3 (1 << BNX2X_CHIP_E3_OFST) 22198c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_E3B0 (1 << BNX2X_CHIP_E3B0_OFST) 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_ALL ((1 << BNX2X_CHIP_MAX_OFST) - 1) 22228c2ecf20Sopenharmony_ci#define BNX2X_CHIP_MASK_E1X (BNX2X_CHIP_MASK_E1 | BNX2X_CHIP_MASK_E1H) 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cistatic int bnx2x_test_registers(struct bnx2x *bp) 22258c2ecf20Sopenharmony_ci{ 22268c2ecf20Sopenharmony_ci int idx, i, rc = -ENODEV; 22278c2ecf20Sopenharmony_ci u32 wr_val = 0, hw; 22288c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 22298c2ecf20Sopenharmony_ci static const struct { 22308c2ecf20Sopenharmony_ci u32 hw; 22318c2ecf20Sopenharmony_ci u32 offset0; 22328c2ecf20Sopenharmony_ci u32 offset1; 22338c2ecf20Sopenharmony_ci u32 mask; 22348c2ecf20Sopenharmony_ci } reg_tbl[] = { 22358c2ecf20Sopenharmony_ci/* 0 */ { BNX2X_CHIP_MASK_ALL, 22368c2ecf20Sopenharmony_ci BRB1_REG_PAUSE_LOW_THRESHOLD_0, 4, 0x000003ff }, 22378c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22388c2ecf20Sopenharmony_ci DORQ_REG_DB_ADDR0, 4, 0xffffffff }, 22398c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E1X, 22408c2ecf20Sopenharmony_ci HC_REG_AGG_INT_0, 4, 0x000003ff }, 22418c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22428c2ecf20Sopenharmony_ci PBF_REG_MAC_IF0_ENABLE, 4, 0x00000001 }, 22438c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2 | BNX2X_CHIP_MASK_E3, 22448c2ecf20Sopenharmony_ci PBF_REG_P0_INIT_CRD, 4, 0x000007ff }, 22458c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E3B0, 22468c2ecf20Sopenharmony_ci PBF_REG_INIT_CRD_Q0, 4, 0x000007ff }, 22478c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22488c2ecf20Sopenharmony_ci PRS_REG_CID_PORT_0, 4, 0x00ffffff }, 22498c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22508c2ecf20Sopenharmony_ci PXP2_REG_PSWRQ_CDU0_L2P, 4, 0x000fffff }, 22518c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22528c2ecf20Sopenharmony_ci PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, 22538c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22548c2ecf20Sopenharmony_ci PXP2_REG_PSWRQ_TM0_L2P, 4, 0x000fffff }, 22558c2ecf20Sopenharmony_ci/* 10 */ { BNX2X_CHIP_MASK_ALL, 22568c2ecf20Sopenharmony_ci PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, 22578c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22588c2ecf20Sopenharmony_ci PXP2_REG_PSWRQ_TSDM0_L2P, 4, 0x000fffff }, 22598c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22608c2ecf20Sopenharmony_ci QM_REG_CONNNUM_0, 4, 0x000fffff }, 22618c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22628c2ecf20Sopenharmony_ci TM_REG_LIN0_MAX_ACTIVE_CID, 4, 0x0003ffff }, 22638c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22648c2ecf20Sopenharmony_ci SRC_REG_KEYRSS0_0, 40, 0xffffffff }, 22658c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22668c2ecf20Sopenharmony_ci SRC_REG_KEYRSS0_7, 40, 0xffffffff }, 22678c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22688c2ecf20Sopenharmony_ci XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 }, 22698c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22708c2ecf20Sopenharmony_ci XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 }, 22718c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22728c2ecf20Sopenharmony_ci XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff }, 22738c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22748c2ecf20Sopenharmony_ci NIG_REG_LLH0_T_BIT, 4, 0x00000001 }, 22758c2ecf20Sopenharmony_ci/* 20 */ { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, 22768c2ecf20Sopenharmony_ci NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, 22778c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, 22788c2ecf20Sopenharmony_ci NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, 22798c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22808c2ecf20Sopenharmony_ci NIG_REG_XCM0_OUT_EN, 4, 0x00000001 }, 22818c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22828c2ecf20Sopenharmony_ci NIG_REG_BRB0_OUT_EN, 4, 0x00000001 }, 22838c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22848c2ecf20Sopenharmony_ci NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 }, 22858c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22868c2ecf20Sopenharmony_ci NIG_REG_LLH0_ACPI_PAT_6_LEN, 68, 0x000000ff }, 22878c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22888c2ecf20Sopenharmony_ci NIG_REG_LLH0_ACPI_PAT_0_CRC, 68, 0xffffffff }, 22898c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22908c2ecf20Sopenharmony_ci NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff }, 22918c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22928c2ecf20Sopenharmony_ci NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff }, 22938c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22948c2ecf20Sopenharmony_ci NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 }, 22958c2ecf20Sopenharmony_ci/* 30 */ { BNX2X_CHIP_MASK_ALL, 22968c2ecf20Sopenharmony_ci NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, 22978c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 22988c2ecf20Sopenharmony_ci NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, 22998c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 23008c2ecf20Sopenharmony_ci NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff }, 23018c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, 23028c2ecf20Sopenharmony_ci NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 }, 23038c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 23048c2ecf20Sopenharmony_ci NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001}, 23058c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 23068c2ecf20Sopenharmony_ci NIG_REG_STATUS_INTERRUPT_PORT0, 4, 0x07ffffff }, 23078c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, 23088c2ecf20Sopenharmony_ci NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 }, 23098c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, 23108c2ecf20Sopenharmony_ci NIG_REG_SERDES0_CTRL_PHY_ADDR, 16, 0x0000001f }, 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci { BNX2X_CHIP_MASK_ALL, 0xffffffff, 0, 0x00000000 } 23138c2ecf20Sopenharmony_ci }; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 23168c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 23178c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 23188c2ecf20Sopenharmony_ci return rc; 23198c2ecf20Sopenharmony_ci } 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) 23228c2ecf20Sopenharmony_ci hw = BNX2X_CHIP_MASK_E1; 23238c2ecf20Sopenharmony_ci else if (CHIP_IS_E1H(bp)) 23248c2ecf20Sopenharmony_ci hw = BNX2X_CHIP_MASK_E1H; 23258c2ecf20Sopenharmony_ci else if (CHIP_IS_E2(bp)) 23268c2ecf20Sopenharmony_ci hw = BNX2X_CHIP_MASK_E2; 23278c2ecf20Sopenharmony_ci else if (CHIP_IS_E3B0(bp)) 23288c2ecf20Sopenharmony_ci hw = BNX2X_CHIP_MASK_E3B0; 23298c2ecf20Sopenharmony_ci else /* e3 A0 */ 23308c2ecf20Sopenharmony_ci hw = BNX2X_CHIP_MASK_E3; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* Repeat the test twice: 23338c2ecf20Sopenharmony_ci * First by writing 0x00000000, second by writing 0xffffffff 23348c2ecf20Sopenharmony_ci */ 23358c2ecf20Sopenharmony_ci for (idx = 0; idx < 2; idx++) { 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci switch (idx) { 23388c2ecf20Sopenharmony_ci case 0: 23398c2ecf20Sopenharmony_ci wr_val = 0; 23408c2ecf20Sopenharmony_ci break; 23418c2ecf20Sopenharmony_ci case 1: 23428c2ecf20Sopenharmony_ci wr_val = 0xffffffff; 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) { 23478c2ecf20Sopenharmony_ci u32 offset, mask, save_val, val; 23488c2ecf20Sopenharmony_ci if (!(hw & reg_tbl[i].hw)) 23498c2ecf20Sopenharmony_ci continue; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1; 23528c2ecf20Sopenharmony_ci mask = reg_tbl[i].mask; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci save_val = REG_RD(bp, offset); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci REG_WR(bp, offset, wr_val & mask); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci val = REG_RD(bp, offset); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci /* Restore the original register's value */ 23618c2ecf20Sopenharmony_ci REG_WR(bp, offset, save_val); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci /* verify value is as expected */ 23648c2ecf20Sopenharmony_ci if ((val & mask) != (wr_val & mask)) { 23658c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 23668c2ecf20Sopenharmony_ci "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n", 23678c2ecf20Sopenharmony_ci offset, val, wr_val, mask); 23688c2ecf20Sopenharmony_ci goto test_reg_exit; 23698c2ecf20Sopenharmony_ci } 23708c2ecf20Sopenharmony_ci } 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci rc = 0; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_citest_reg_exit: 23768c2ecf20Sopenharmony_ci return rc; 23778c2ecf20Sopenharmony_ci} 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_cistatic int bnx2x_test_memory(struct bnx2x *bp) 23808c2ecf20Sopenharmony_ci{ 23818c2ecf20Sopenharmony_ci int i, j, rc = -ENODEV; 23828c2ecf20Sopenharmony_ci u32 val, index; 23838c2ecf20Sopenharmony_ci static const struct { 23848c2ecf20Sopenharmony_ci u32 offset; 23858c2ecf20Sopenharmony_ci int size; 23868c2ecf20Sopenharmony_ci } mem_tbl[] = { 23878c2ecf20Sopenharmony_ci { CCM_REG_XX_DESCR_TABLE, CCM_REG_XX_DESCR_TABLE_SIZE }, 23888c2ecf20Sopenharmony_ci { CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE }, 23898c2ecf20Sopenharmony_ci { CFC_REG_LINK_LIST, CFC_REG_LINK_LIST_SIZE }, 23908c2ecf20Sopenharmony_ci { DMAE_REG_CMD_MEM, DMAE_REG_CMD_MEM_SIZE }, 23918c2ecf20Sopenharmony_ci { TCM_REG_XX_DESCR_TABLE, TCM_REG_XX_DESCR_TABLE_SIZE }, 23928c2ecf20Sopenharmony_ci { UCM_REG_XX_DESCR_TABLE, UCM_REG_XX_DESCR_TABLE_SIZE }, 23938c2ecf20Sopenharmony_ci { XCM_REG_XX_DESCR_TABLE, XCM_REG_XX_DESCR_TABLE_SIZE }, 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci { 0xffffffff, 0 } 23968c2ecf20Sopenharmony_ci }; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci static const struct { 23998c2ecf20Sopenharmony_ci char *name; 24008c2ecf20Sopenharmony_ci u32 offset; 24018c2ecf20Sopenharmony_ci u32 hw_mask[BNX2X_CHIP_MAX_OFST]; 24028c2ecf20Sopenharmony_ci } prty_tbl[] = { 24038c2ecf20Sopenharmony_ci { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, 24048c2ecf20Sopenharmony_ci {0x3ffc0, 0, 0, 0} }, 24058c2ecf20Sopenharmony_ci { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, 24068c2ecf20Sopenharmony_ci {0x2, 0x2, 0, 0} }, 24078c2ecf20Sopenharmony_ci { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, 24088c2ecf20Sopenharmony_ci {0, 0, 0, 0} }, 24098c2ecf20Sopenharmony_ci { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, 24108c2ecf20Sopenharmony_ci {0x3ffc0, 0, 0, 0} }, 24118c2ecf20Sopenharmony_ci { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, 24128c2ecf20Sopenharmony_ci {0x3ffc0, 0, 0, 0} }, 24138c2ecf20Sopenharmony_ci { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, 24148c2ecf20Sopenharmony_ci {0x3ffc1, 0, 0, 0} }, 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci { NULL, 0xffffffff, {0, 0, 0, 0} } 24178c2ecf20Sopenharmony_ci }; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 24208c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 24218c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 24228c2ecf20Sopenharmony_ci return rc; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) 24268c2ecf20Sopenharmony_ci index = BNX2X_CHIP_E1_OFST; 24278c2ecf20Sopenharmony_ci else if (CHIP_IS_E1H(bp)) 24288c2ecf20Sopenharmony_ci index = BNX2X_CHIP_E1H_OFST; 24298c2ecf20Sopenharmony_ci else if (CHIP_IS_E2(bp)) 24308c2ecf20Sopenharmony_ci index = BNX2X_CHIP_E2_OFST; 24318c2ecf20Sopenharmony_ci else /* e3 */ 24328c2ecf20Sopenharmony_ci index = BNX2X_CHIP_E3_OFST; 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci /* pre-Check the parity status */ 24358c2ecf20Sopenharmony_ci for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { 24368c2ecf20Sopenharmony_ci val = REG_RD(bp, prty_tbl[i].offset); 24378c2ecf20Sopenharmony_ci if (val & ~(prty_tbl[i].hw_mask[index])) { 24388c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 24398c2ecf20Sopenharmony_ci "%s is 0x%x\n", prty_tbl[i].name, val); 24408c2ecf20Sopenharmony_ci goto test_mem_exit; 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci /* Go through all the memories */ 24458c2ecf20Sopenharmony_ci for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) 24468c2ecf20Sopenharmony_ci for (j = 0; j < mem_tbl[i].size; j++) 24478c2ecf20Sopenharmony_ci REG_RD(bp, mem_tbl[i].offset + j*4); 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci /* Check the parity status */ 24508c2ecf20Sopenharmony_ci for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { 24518c2ecf20Sopenharmony_ci val = REG_RD(bp, prty_tbl[i].offset); 24528c2ecf20Sopenharmony_ci if (val & ~(prty_tbl[i].hw_mask[index])) { 24538c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 24548c2ecf20Sopenharmony_ci "%s is 0x%x\n", prty_tbl[i].name, val); 24558c2ecf20Sopenharmony_ci goto test_mem_exit; 24568c2ecf20Sopenharmony_ci } 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci rc = 0; 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_citest_mem_exit: 24628c2ecf20Sopenharmony_ci return rc; 24638c2ecf20Sopenharmony_ci} 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_cistatic void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes) 24668c2ecf20Sopenharmony_ci{ 24678c2ecf20Sopenharmony_ci int cnt = 1400; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci if (link_up) { 24708c2ecf20Sopenharmony_ci while (bnx2x_link_test(bp, is_serdes) && cnt--) 24718c2ecf20Sopenharmony_ci msleep(20); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (cnt <= 0 && bnx2x_link_test(bp, is_serdes)) 24748c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Timeout waiting for link up\n"); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci cnt = 1400; 24778c2ecf20Sopenharmony_ci while (!bp->link_vars.link_up && cnt--) 24788c2ecf20Sopenharmony_ci msleep(20); 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci if (cnt <= 0 && !bp->link_vars.link_up) 24818c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 24828c2ecf20Sopenharmony_ci "Timeout waiting for link init\n"); 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci} 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_cistatic int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode) 24878c2ecf20Sopenharmony_ci{ 24888c2ecf20Sopenharmony_ci unsigned int pkt_size, num_pkts, i; 24898c2ecf20Sopenharmony_ci struct sk_buff *skb; 24908c2ecf20Sopenharmony_ci unsigned char *packet; 24918c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp_rx = &bp->fp[0]; 24928c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp_tx = &bp->fp[0]; 24938c2ecf20Sopenharmony_ci struct bnx2x_fp_txdata *txdata = fp_tx->txdata_ptr[0]; 24948c2ecf20Sopenharmony_ci u16 tx_start_idx, tx_idx; 24958c2ecf20Sopenharmony_ci u16 rx_start_idx, rx_idx; 24968c2ecf20Sopenharmony_ci u16 pkt_prod, bd_prod; 24978c2ecf20Sopenharmony_ci struct sw_tx_bd *tx_buf; 24988c2ecf20Sopenharmony_ci struct eth_tx_start_bd *tx_start_bd; 24998c2ecf20Sopenharmony_ci dma_addr_t mapping; 25008c2ecf20Sopenharmony_ci union eth_rx_cqe *cqe; 25018c2ecf20Sopenharmony_ci u8 cqe_fp_flags, cqe_fp_type; 25028c2ecf20Sopenharmony_ci struct sw_rx_bd *rx_buf; 25038c2ecf20Sopenharmony_ci u16 len; 25048c2ecf20Sopenharmony_ci int rc = -ENODEV; 25058c2ecf20Sopenharmony_ci u8 *data; 25068c2ecf20Sopenharmony_ci struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, 25078c2ecf20Sopenharmony_ci txdata->txq_index); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* check the loopback mode */ 25108c2ecf20Sopenharmony_ci switch (loopback_mode) { 25118c2ecf20Sopenharmony_ci case BNX2X_PHY_LOOPBACK: 25128c2ecf20Sopenharmony_ci if (bp->link_params.loopback_mode != LOOPBACK_XGXS) { 25138c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "PHY loopback not supported\n"); 25148c2ecf20Sopenharmony_ci return -EINVAL; 25158c2ecf20Sopenharmony_ci } 25168c2ecf20Sopenharmony_ci break; 25178c2ecf20Sopenharmony_ci case BNX2X_MAC_LOOPBACK: 25188c2ecf20Sopenharmony_ci if (CHIP_IS_E3(bp)) { 25198c2ecf20Sopenharmony_ci int cfg_idx = bnx2x_get_link_cfg_idx(bp); 25208c2ecf20Sopenharmony_ci if (bp->port.supported[cfg_idx] & 25218c2ecf20Sopenharmony_ci (SUPPORTED_10000baseT_Full | 25228c2ecf20Sopenharmony_ci SUPPORTED_20000baseMLD2_Full | 25238c2ecf20Sopenharmony_ci SUPPORTED_20000baseKR2_Full)) 25248c2ecf20Sopenharmony_ci bp->link_params.loopback_mode = LOOPBACK_XMAC; 25258c2ecf20Sopenharmony_ci else 25268c2ecf20Sopenharmony_ci bp->link_params.loopback_mode = LOOPBACK_UMAC; 25278c2ecf20Sopenharmony_ci } else 25288c2ecf20Sopenharmony_ci bp->link_params.loopback_mode = LOOPBACK_BMAC; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci bnx2x_phy_init(&bp->link_params, &bp->link_vars); 25318c2ecf20Sopenharmony_ci break; 25328c2ecf20Sopenharmony_ci case BNX2X_EXT_LOOPBACK: 25338c2ecf20Sopenharmony_ci if (bp->link_params.loopback_mode != LOOPBACK_EXT) { 25348c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 25358c2ecf20Sopenharmony_ci "Can't configure external loopback\n"); 25368c2ecf20Sopenharmony_ci return -EINVAL; 25378c2ecf20Sopenharmony_ci } 25388c2ecf20Sopenharmony_ci break; 25398c2ecf20Sopenharmony_ci default: 25408c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n"); 25418c2ecf20Sopenharmony_ci return -EINVAL; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci /* prepare the loopback packet */ 25458c2ecf20Sopenharmony_ci pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ? 25468c2ecf20Sopenharmony_ci bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN); 25478c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, fp_rx->rx_buf_size); 25488c2ecf20Sopenharmony_ci if (!skb) { 25498c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Can't allocate skb\n"); 25508c2ecf20Sopenharmony_ci rc = -ENOMEM; 25518c2ecf20Sopenharmony_ci goto test_loopback_exit; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci packet = skb_put(skb, pkt_size); 25548c2ecf20Sopenharmony_ci memcpy(packet, bp->dev->dev_addr, ETH_ALEN); 25558c2ecf20Sopenharmony_ci eth_zero_addr(packet + ETH_ALEN); 25568c2ecf20Sopenharmony_ci memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN)); 25578c2ecf20Sopenharmony_ci for (i = ETH_HLEN; i < pkt_size; i++) 25588c2ecf20Sopenharmony_ci packet[i] = (unsigned char) (i & 0xff); 25598c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, skb->data, 25608c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 25618c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { 25628c2ecf20Sopenharmony_ci rc = -ENOMEM; 25638c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 25648c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Unable to map SKB\n"); 25658c2ecf20Sopenharmony_ci goto test_loopback_exit; 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci /* send the loopback packet */ 25698c2ecf20Sopenharmony_ci num_pkts = 0; 25708c2ecf20Sopenharmony_ci tx_start_idx = le16_to_cpu(*txdata->tx_cons_sb); 25718c2ecf20Sopenharmony_ci rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci netdev_tx_sent_queue(txq, skb->len); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci pkt_prod = txdata->tx_pkt_prod++; 25768c2ecf20Sopenharmony_ci tx_buf = &txdata->tx_buf_ring[TX_BD(pkt_prod)]; 25778c2ecf20Sopenharmony_ci tx_buf->first_bd = txdata->tx_bd_prod; 25788c2ecf20Sopenharmony_ci tx_buf->skb = skb; 25798c2ecf20Sopenharmony_ci tx_buf->flags = 0; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci bd_prod = TX_BD(txdata->tx_bd_prod); 25828c2ecf20Sopenharmony_ci tx_start_bd = &txdata->tx_desc_ring[bd_prod].start_bd; 25838c2ecf20Sopenharmony_ci tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); 25848c2ecf20Sopenharmony_ci tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); 25858c2ecf20Sopenharmony_ci tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */ 25868c2ecf20Sopenharmony_ci tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); 25878c2ecf20Sopenharmony_ci tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); 25888c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; 25898c2ecf20Sopenharmony_ci SET_FLAG(tx_start_bd->general_data, 25908c2ecf20Sopenharmony_ci ETH_TX_START_BD_HDR_NBDS, 25918c2ecf20Sopenharmony_ci 1); 25928c2ecf20Sopenharmony_ci SET_FLAG(tx_start_bd->general_data, 25938c2ecf20Sopenharmony_ci ETH_TX_START_BD_PARSE_NBDS, 25948c2ecf20Sopenharmony_ci 0); 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci /* turn on parsing and get a BD */ 25978c2ecf20Sopenharmony_ci bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp)) { 26008c2ecf20Sopenharmony_ci u16 global_data = 0; 26018c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e1x *pbd_e1x = 26028c2ecf20Sopenharmony_ci &txdata->tx_desc_ring[bd_prod].parse_bd_e1x; 26038c2ecf20Sopenharmony_ci memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); 26048c2ecf20Sopenharmony_ci SET_FLAG(global_data, 26058c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E1X_ETH_ADDR_TYPE, UNICAST_ADDRESS); 26068c2ecf20Sopenharmony_ci pbd_e1x->global_data = cpu_to_le16(global_data); 26078c2ecf20Sopenharmony_ci } else { 26088c2ecf20Sopenharmony_ci u32 parsing_data = 0; 26098c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e2 *pbd_e2 = 26108c2ecf20Sopenharmony_ci &txdata->tx_desc_ring[bd_prod].parse_bd_e2; 26118c2ecf20Sopenharmony_ci memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); 26128c2ecf20Sopenharmony_ci SET_FLAG(parsing_data, 26138c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_ETH_ADDR_TYPE, UNICAST_ADDRESS); 26148c2ecf20Sopenharmony_ci pbd_e2->parsing_data = cpu_to_le32(parsing_data); 26158c2ecf20Sopenharmony_ci } 26168c2ecf20Sopenharmony_ci wmb(); 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci txdata->tx_db.data.prod += 2; 26198c2ecf20Sopenharmony_ci /* make sure descriptor update is observed by the HW */ 26208c2ecf20Sopenharmony_ci wmb(); 26218c2ecf20Sopenharmony_ci DOORBELL_RELAXED(bp, txdata->cid, txdata->tx_db.raw); 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci barrier(); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci num_pkts++; 26268c2ecf20Sopenharmony_ci txdata->tx_bd_prod += 2; /* start + pbd */ 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci udelay(100); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci tx_idx = le16_to_cpu(*txdata->tx_cons_sb); 26318c2ecf20Sopenharmony_ci if (tx_idx != tx_start_idx + num_pkts) 26328c2ecf20Sopenharmony_ci goto test_loopback_exit; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci /* Unlike HC IGU won't generate an interrupt for status block 26358c2ecf20Sopenharmony_ci * updates that have been performed while interrupts were 26368c2ecf20Sopenharmony_ci * disabled. 26378c2ecf20Sopenharmony_ci */ 26388c2ecf20Sopenharmony_ci if (bp->common.int_block == INT_BLOCK_IGU) { 26398c2ecf20Sopenharmony_ci /* Disable local BHes to prevent a dead-lock situation between 26408c2ecf20Sopenharmony_ci * sch_direct_xmit() and bnx2x_run_loopback() (calling 26418c2ecf20Sopenharmony_ci * bnx2x_tx_int()), as both are taking netif_tx_lock(). 26428c2ecf20Sopenharmony_ci */ 26438c2ecf20Sopenharmony_ci local_bh_disable(); 26448c2ecf20Sopenharmony_ci bnx2x_tx_int(bp, txdata); 26458c2ecf20Sopenharmony_ci local_bh_enable(); 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); 26498c2ecf20Sopenharmony_ci if (rx_idx != rx_start_idx + num_pkts) 26508c2ecf20Sopenharmony_ci goto test_loopback_exit; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)]; 26538c2ecf20Sopenharmony_ci cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; 26548c2ecf20Sopenharmony_ci cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE; 26558c2ecf20Sopenharmony_ci if (!CQE_TYPE_FAST(cqe_fp_type) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) 26568c2ecf20Sopenharmony_ci goto test_loopback_rx_exit; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci len = le16_to_cpu(cqe->fast_path_cqe.pkt_len_or_gro_seg_len); 26598c2ecf20Sopenharmony_ci if (len != pkt_size) 26608c2ecf20Sopenharmony_ci goto test_loopback_rx_exit; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)]; 26638c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&bp->pdev->dev, 26648c2ecf20Sopenharmony_ci dma_unmap_addr(rx_buf, mapping), 26658c2ecf20Sopenharmony_ci fp_rx->rx_buf_size, DMA_FROM_DEVICE); 26668c2ecf20Sopenharmony_ci data = rx_buf->data + NET_SKB_PAD + cqe->fast_path_cqe.placement_offset; 26678c2ecf20Sopenharmony_ci for (i = ETH_HLEN; i < pkt_size; i++) 26688c2ecf20Sopenharmony_ci if (*(data + i) != (unsigned char) (i & 0xff)) 26698c2ecf20Sopenharmony_ci goto test_loopback_rx_exit; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci rc = 0; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_citest_loopback_rx_exit: 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons); 26768c2ecf20Sopenharmony_ci fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod); 26778c2ecf20Sopenharmony_ci fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons); 26788c2ecf20Sopenharmony_ci fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod); 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci /* Update producers */ 26818c2ecf20Sopenharmony_ci bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod, 26828c2ecf20Sopenharmony_ci fp_rx->rx_sge_prod); 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_citest_loopback_exit: 26858c2ecf20Sopenharmony_ci bp->link_params.loopback_mode = LOOPBACK_NONE; 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci return rc; 26888c2ecf20Sopenharmony_ci} 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_cistatic int bnx2x_test_loopback(struct bnx2x *bp) 26918c2ecf20Sopenharmony_ci{ 26928c2ecf20Sopenharmony_ci int rc = 0, res; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci if (BP_NOMCP(bp)) 26958c2ecf20Sopenharmony_ci return rc; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 26988c2ecf20Sopenharmony_ci return BNX2X_LOOPBACK_FAILED; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci bnx2x_netif_stop(bp, 1); 27018c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci res = bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK); 27048c2ecf20Sopenharmony_ci if (res) { 27058c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, " PHY loopback failed (res %d)\n", res); 27068c2ecf20Sopenharmony_ci rc |= BNX2X_PHY_LOOPBACK_FAILED; 27078c2ecf20Sopenharmony_ci } 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci res = bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK); 27108c2ecf20Sopenharmony_ci if (res) { 27118c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, " MAC loopback failed (res %d)\n", res); 27128c2ecf20Sopenharmony_ci rc |= BNX2X_MAC_LOOPBACK_FAILED; 27138c2ecf20Sopenharmony_ci } 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 27168c2ecf20Sopenharmony_ci bnx2x_netif_start(bp); 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci return rc; 27198c2ecf20Sopenharmony_ci} 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_cistatic int bnx2x_test_ext_loopback(struct bnx2x *bp) 27228c2ecf20Sopenharmony_ci{ 27238c2ecf20Sopenharmony_ci int rc; 27248c2ecf20Sopenharmony_ci u8 is_serdes = 27258c2ecf20Sopenharmony_ci (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci if (BP_NOMCP(bp)) 27288c2ecf20Sopenharmony_ci return -ENODEV; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 27318c2ecf20Sopenharmony_ci return BNX2X_EXT_LOOPBACK_FAILED; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_NORMAL, false); 27348c2ecf20Sopenharmony_ci rc = bnx2x_nic_load(bp, LOAD_LOOPBACK_EXT); 27358c2ecf20Sopenharmony_ci if (rc) { 27368c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 27378c2ecf20Sopenharmony_ci "Can't perform self-test, nic_load (for external lb) failed\n"); 27388c2ecf20Sopenharmony_ci return -ENODEV; 27398c2ecf20Sopenharmony_ci } 27408c2ecf20Sopenharmony_ci bnx2x_wait_for_link(bp, 1, is_serdes); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci bnx2x_netif_stop(bp, 1); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci rc = bnx2x_run_loopback(bp, BNX2X_EXT_LOOPBACK); 27458c2ecf20Sopenharmony_ci if (rc) 27468c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "EXT loopback failed (res %d)\n", rc); 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci bnx2x_netif_start(bp); 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci return rc; 27518c2ecf20Sopenharmony_ci} 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_cistruct code_entry { 27548c2ecf20Sopenharmony_ci u32 sram_start_addr; 27558c2ecf20Sopenharmony_ci u32 code_attribute; 27568c2ecf20Sopenharmony_ci#define CODE_IMAGE_TYPE_MASK 0xf0800003 27578c2ecf20Sopenharmony_ci#define CODE_IMAGE_VNTAG_PROFILES_DATA 0xd0000003 27588c2ecf20Sopenharmony_ci#define CODE_IMAGE_LENGTH_MASK 0x007ffffc 27598c2ecf20Sopenharmony_ci#define CODE_IMAGE_TYPE_EXTENDED_DIR 0xe0000000 27608c2ecf20Sopenharmony_ci u32 nvm_start_addr; 27618c2ecf20Sopenharmony_ci}; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci#define CODE_ENTRY_MAX 16 27648c2ecf20Sopenharmony_ci#define CODE_ENTRY_EXTENDED_DIR_IDX 15 27658c2ecf20Sopenharmony_ci#define MAX_IMAGES_IN_EXTENDED_DIR 64 27668c2ecf20Sopenharmony_ci#define NVRAM_DIR_OFFSET 0x14 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci#define EXTENDED_DIR_EXISTS(code) \ 27698c2ecf20Sopenharmony_ci ((code & CODE_IMAGE_TYPE_MASK) == CODE_IMAGE_TYPE_EXTENDED_DIR && \ 27708c2ecf20Sopenharmony_ci (code & CODE_IMAGE_LENGTH_MASK) != 0) 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci#define CRC32_RESIDUAL 0xdebb20e3 27738c2ecf20Sopenharmony_ci#define CRC_BUFF_SIZE 256 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_cistatic int bnx2x_nvram_crc(struct bnx2x *bp, 27768c2ecf20Sopenharmony_ci int offset, 27778c2ecf20Sopenharmony_ci int size, 27788c2ecf20Sopenharmony_ci u8 *buff) 27798c2ecf20Sopenharmony_ci{ 27808c2ecf20Sopenharmony_ci u32 crc = ~0; 27818c2ecf20Sopenharmony_ci int rc = 0, done = 0; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 27848c2ecf20Sopenharmony_ci "NVRAM CRC from 0x%08x to 0x%08x\n", offset, offset + size); 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci while (done < size) { 27878c2ecf20Sopenharmony_ci int count = min_t(int, size - done, CRC_BUFF_SIZE); 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read(bp, offset + done, buff, count); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci if (rc) 27928c2ecf20Sopenharmony_ci return rc; 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci crc = crc32_le(crc, buff, count); 27958c2ecf20Sopenharmony_ci done += count; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci if (crc != CRC32_RESIDUAL) 27998c2ecf20Sopenharmony_ci rc = -EINVAL; 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci return rc; 28028c2ecf20Sopenharmony_ci} 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_cistatic int bnx2x_test_nvram_dir(struct bnx2x *bp, 28058c2ecf20Sopenharmony_ci struct code_entry *entry, 28068c2ecf20Sopenharmony_ci u8 *buff) 28078c2ecf20Sopenharmony_ci{ 28088c2ecf20Sopenharmony_ci size_t size = entry->code_attribute & CODE_IMAGE_LENGTH_MASK; 28098c2ecf20Sopenharmony_ci u32 type = entry->code_attribute & CODE_IMAGE_TYPE_MASK; 28108c2ecf20Sopenharmony_ci int rc; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci /* Zero-length images and AFEX profiles do not have CRC */ 28138c2ecf20Sopenharmony_ci if (size == 0 || type == CODE_IMAGE_VNTAG_PROFILES_DATA) 28148c2ecf20Sopenharmony_ci return 0; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci rc = bnx2x_nvram_crc(bp, entry->nvm_start_addr, size, buff); 28178c2ecf20Sopenharmony_ci if (rc) 28188c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 28198c2ecf20Sopenharmony_ci "image %x has failed crc test (rc %d)\n", type, rc); 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci return rc; 28228c2ecf20Sopenharmony_ci} 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_cistatic int bnx2x_test_dir_entry(struct bnx2x *bp, u32 addr, u8 *buff) 28258c2ecf20Sopenharmony_ci{ 28268c2ecf20Sopenharmony_ci int rc; 28278c2ecf20Sopenharmony_ci struct code_entry entry; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read32(bp, addr, (u32 *)&entry, sizeof(entry)); 28308c2ecf20Sopenharmony_ci if (rc) 28318c2ecf20Sopenharmony_ci return rc; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci return bnx2x_test_nvram_dir(bp, &entry, buff); 28348c2ecf20Sopenharmony_ci} 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_cistatic int bnx2x_test_nvram_ext_dirs(struct bnx2x *bp, u8 *buff) 28378c2ecf20Sopenharmony_ci{ 28388c2ecf20Sopenharmony_ci u32 rc, cnt, dir_offset = NVRAM_DIR_OFFSET; 28398c2ecf20Sopenharmony_ci struct code_entry entry; 28408c2ecf20Sopenharmony_ci int i; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read32(bp, 28438c2ecf20Sopenharmony_ci dir_offset + 28448c2ecf20Sopenharmony_ci sizeof(entry) * CODE_ENTRY_EXTENDED_DIR_IDX, 28458c2ecf20Sopenharmony_ci (u32 *)&entry, sizeof(entry)); 28468c2ecf20Sopenharmony_ci if (rc) 28478c2ecf20Sopenharmony_ci return rc; 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci if (!EXTENDED_DIR_EXISTS(entry.code_attribute)) 28508c2ecf20Sopenharmony_ci return 0; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read32(bp, entry.nvm_start_addr, 28538c2ecf20Sopenharmony_ci &cnt, sizeof(u32)); 28548c2ecf20Sopenharmony_ci if (rc) 28558c2ecf20Sopenharmony_ci return rc; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci dir_offset = entry.nvm_start_addr + 8; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci for (i = 0; i < cnt && i < MAX_IMAGES_IN_EXTENDED_DIR; i++) { 28608c2ecf20Sopenharmony_ci rc = bnx2x_test_dir_entry(bp, dir_offset + 28618c2ecf20Sopenharmony_ci sizeof(struct code_entry) * i, 28628c2ecf20Sopenharmony_ci buff); 28638c2ecf20Sopenharmony_ci if (rc) 28648c2ecf20Sopenharmony_ci return rc; 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci return 0; 28688c2ecf20Sopenharmony_ci} 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_cistatic int bnx2x_test_nvram_dirs(struct bnx2x *bp, u8 *buff) 28718c2ecf20Sopenharmony_ci{ 28728c2ecf20Sopenharmony_ci u32 rc, dir_offset = NVRAM_DIR_OFFSET; 28738c2ecf20Sopenharmony_ci int i; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "NVRAM DIRS CRC test-set\n"); 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci for (i = 0; i < CODE_ENTRY_EXTENDED_DIR_IDX; i++) { 28788c2ecf20Sopenharmony_ci rc = bnx2x_test_dir_entry(bp, dir_offset + 28798c2ecf20Sopenharmony_ci sizeof(struct code_entry) * i, 28808c2ecf20Sopenharmony_ci buff); 28818c2ecf20Sopenharmony_ci if (rc) 28828c2ecf20Sopenharmony_ci return rc; 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci return bnx2x_test_nvram_ext_dirs(bp, buff); 28868c2ecf20Sopenharmony_ci} 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_cistruct crc_pair { 28898c2ecf20Sopenharmony_ci int offset; 28908c2ecf20Sopenharmony_ci int size; 28918c2ecf20Sopenharmony_ci}; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_cistatic int bnx2x_test_nvram_tbl(struct bnx2x *bp, 28948c2ecf20Sopenharmony_ci const struct crc_pair *nvram_tbl, u8 *buf) 28958c2ecf20Sopenharmony_ci{ 28968c2ecf20Sopenharmony_ci int i; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci for (i = 0; nvram_tbl[i].size; i++) { 28998c2ecf20Sopenharmony_ci int rc = bnx2x_nvram_crc(bp, nvram_tbl[i].offset, 29008c2ecf20Sopenharmony_ci nvram_tbl[i].size, buf); 29018c2ecf20Sopenharmony_ci if (rc) { 29028c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 29038c2ecf20Sopenharmony_ci "nvram_tbl[%d] has failed crc test (rc %d)\n", 29048c2ecf20Sopenharmony_ci i, rc); 29058c2ecf20Sopenharmony_ci return rc; 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci } 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci return 0; 29108c2ecf20Sopenharmony_ci} 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_cistatic int bnx2x_test_nvram(struct bnx2x *bp) 29138c2ecf20Sopenharmony_ci{ 29148c2ecf20Sopenharmony_ci static const struct crc_pair nvram_tbl[] = { 29158c2ecf20Sopenharmony_ci { 0, 0x14 }, /* bootstrap */ 29168c2ecf20Sopenharmony_ci { 0x14, 0xec }, /* dir */ 29178c2ecf20Sopenharmony_ci { 0x100, 0x350 }, /* manuf_info */ 29188c2ecf20Sopenharmony_ci { 0x450, 0xf0 }, /* feature_info */ 29198c2ecf20Sopenharmony_ci { 0x640, 0x64 }, /* upgrade_key_info */ 29208c2ecf20Sopenharmony_ci { 0x708, 0x70 }, /* manuf_key_info */ 29218c2ecf20Sopenharmony_ci { 0, 0 } 29228c2ecf20Sopenharmony_ci }; 29238c2ecf20Sopenharmony_ci static const struct crc_pair nvram_tbl2[] = { 29248c2ecf20Sopenharmony_ci { 0x7e8, 0x350 }, /* manuf_info2 */ 29258c2ecf20Sopenharmony_ci { 0xb38, 0xf0 }, /* feature_info */ 29268c2ecf20Sopenharmony_ci { 0, 0 } 29278c2ecf20Sopenharmony_ci }; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci u8 *buf; 29308c2ecf20Sopenharmony_ci int rc; 29318c2ecf20Sopenharmony_ci u32 magic; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci if (BP_NOMCP(bp)) 29348c2ecf20Sopenharmony_ci return 0; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci buf = kmalloc(CRC_BUFF_SIZE, GFP_KERNEL); 29378c2ecf20Sopenharmony_ci if (!buf) { 29388c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "kmalloc failed\n"); 29398c2ecf20Sopenharmony_ci rc = -ENOMEM; 29408c2ecf20Sopenharmony_ci goto test_nvram_exit; 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci rc = bnx2x_nvram_read32(bp, 0, &magic, sizeof(magic)); 29448c2ecf20Sopenharmony_ci if (rc) { 29458c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 29468c2ecf20Sopenharmony_ci "magic value read (rc %d)\n", rc); 29478c2ecf20Sopenharmony_ci goto test_nvram_exit; 29488c2ecf20Sopenharmony_ci } 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci if (magic != 0x669955aa) { 29518c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 29528c2ecf20Sopenharmony_ci "wrong magic value (0x%08x)\n", magic); 29538c2ecf20Sopenharmony_ci rc = -ENODEV; 29548c2ecf20Sopenharmony_ci goto test_nvram_exit; 29558c2ecf20Sopenharmony_ci } 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "Port 0 CRC test-set\n"); 29588c2ecf20Sopenharmony_ci rc = bnx2x_test_nvram_tbl(bp, nvram_tbl, buf); 29598c2ecf20Sopenharmony_ci if (rc) 29608c2ecf20Sopenharmony_ci goto test_nvram_exit; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp) && !CHIP_IS_57811xx(bp)) { 29638c2ecf20Sopenharmony_ci u32 hide = SHMEM_RD(bp, dev_info.shared_hw_config.config2) & 29648c2ecf20Sopenharmony_ci SHARED_HW_CFG_HIDE_PORT1; 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci if (!hide) { 29678c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 29688c2ecf20Sopenharmony_ci "Port 1 CRC test-set\n"); 29698c2ecf20Sopenharmony_ci rc = bnx2x_test_nvram_tbl(bp, nvram_tbl2, buf); 29708c2ecf20Sopenharmony_ci if (rc) 29718c2ecf20Sopenharmony_ci goto test_nvram_exit; 29728c2ecf20Sopenharmony_ci } 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci rc = bnx2x_test_nvram_dirs(bp, buf); 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_citest_nvram_exit: 29788c2ecf20Sopenharmony_ci kfree(buf); 29798c2ecf20Sopenharmony_ci return rc; 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci/* Send an EMPTY ramrod on the first queue */ 29838c2ecf20Sopenharmony_cistatic int bnx2x_test_intr(struct bnx2x *bp) 29848c2ecf20Sopenharmony_ci{ 29858c2ecf20Sopenharmony_ci struct bnx2x_queue_state_params params = {NULL}; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) { 29888c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 29898c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 29908c2ecf20Sopenharmony_ci return -ENODEV; 29918c2ecf20Sopenharmony_ci } 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci params.q_obj = &bp->sp_objs->q_obj; 29948c2ecf20Sopenharmony_ci params.cmd = BNX2X_Q_CMD_EMPTY; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci __set_bit(RAMROD_COMP_WAIT, ¶ms.ramrod_flags); 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci return bnx2x_queue_state_change(bp, ¶ms); 29998c2ecf20Sopenharmony_ci} 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_cistatic void bnx2x_self_test(struct net_device *dev, 30028c2ecf20Sopenharmony_ci struct ethtool_test *etest, u64 *buf) 30038c2ecf20Sopenharmony_ci{ 30048c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 30058c2ecf20Sopenharmony_ci u8 is_serdes, link_up; 30068c2ecf20Sopenharmony_ci int rc, cnt = 0; 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci if (pci_num_vf(bp->pdev)) { 30098c2ecf20Sopenharmony_ci DP(BNX2X_MSG_IOV, 30108c2ecf20Sopenharmony_ci "VFs are enabled, can not perform self test\n"); 30118c2ecf20Sopenharmony_ci return; 30128c2ecf20Sopenharmony_ci } 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci if (bp->recovery_state != BNX2X_RECOVERY_DONE) { 30158c2ecf20Sopenharmony_ci netdev_err(bp->dev, 30168c2ecf20Sopenharmony_ci "Handling parity error recovery. Try again later\n"); 30178c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30188c2ecf20Sopenharmony_ci return; 30198c2ecf20Sopenharmony_ci } 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 30228c2ecf20Sopenharmony_ci "Self-test command parameters: offline = %d, external_lb = %d\n", 30238c2ecf20Sopenharmony_ci (etest->flags & ETH_TEST_FL_OFFLINE), 30248c2ecf20Sopenharmony_ci (etest->flags & ETH_TEST_FL_EXTERNAL_LB)>>2); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS(bp)); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci if (bnx2x_test_nvram(bp) != 0) { 30298c2ecf20Sopenharmony_ci if (!IS_MF(bp)) 30308c2ecf20Sopenharmony_ci buf[4] = 1; 30318c2ecf20Sopenharmony_ci else 30328c2ecf20Sopenharmony_ci buf[0] = 1; 30338c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30348c2ecf20Sopenharmony_ci } 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci if (!netif_running(dev)) { 30378c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Interface is down\n"); 30388c2ecf20Sopenharmony_ci return; 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0; 30428c2ecf20Sopenharmony_ci link_up = bp->link_vars.link_up; 30438c2ecf20Sopenharmony_ci /* offline tests are not supported in MF mode */ 30448c2ecf20Sopenharmony_ci if ((etest->flags & ETH_TEST_FL_OFFLINE) && !IS_MF(bp)) { 30458c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 30468c2ecf20Sopenharmony_ci u32 val; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci /* save current value of input enable for TX port IF */ 30498c2ecf20Sopenharmony_ci val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4); 30508c2ecf20Sopenharmony_ci /* disable input for TX port IF */ 30518c2ecf20Sopenharmony_ci REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0); 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_NORMAL, false); 30548c2ecf20Sopenharmony_ci rc = bnx2x_nic_load(bp, LOAD_DIAG); 30558c2ecf20Sopenharmony_ci if (rc) { 30568c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30578c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 30588c2ecf20Sopenharmony_ci "Can't perform self-test, nic_load (for offline) failed\n"); 30598c2ecf20Sopenharmony_ci return; 30608c2ecf20Sopenharmony_ci } 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci /* wait until link state is restored */ 30638c2ecf20Sopenharmony_ci bnx2x_wait_for_link(bp, 1, is_serdes); 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci if (bnx2x_test_registers(bp) != 0) { 30668c2ecf20Sopenharmony_ci buf[0] = 1; 30678c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30688c2ecf20Sopenharmony_ci } 30698c2ecf20Sopenharmony_ci if (bnx2x_test_memory(bp) != 0) { 30708c2ecf20Sopenharmony_ci buf[1] = 1; 30718c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30728c2ecf20Sopenharmony_ci } 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci buf[2] = bnx2x_test_loopback(bp); /* internal LB */ 30758c2ecf20Sopenharmony_ci if (buf[2] != 0) 30768c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci if (etest->flags & ETH_TEST_FL_EXTERNAL_LB) { 30798c2ecf20Sopenharmony_ci buf[3] = bnx2x_test_ext_loopback(bp); /* external LB */ 30808c2ecf20Sopenharmony_ci if (buf[3] != 0) 30818c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30828c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 30838c2ecf20Sopenharmony_ci } 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_NORMAL, false); 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci /* restore input for TX port IF */ 30888c2ecf20Sopenharmony_ci REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val); 30898c2ecf20Sopenharmony_ci rc = bnx2x_nic_load(bp, LOAD_NORMAL); 30908c2ecf20Sopenharmony_ci if (rc) { 30918c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 30928c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 30938c2ecf20Sopenharmony_ci "Can't perform self-test, nic_load (for online) failed\n"); 30948c2ecf20Sopenharmony_ci return; 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci /* wait until link state is restored */ 30978c2ecf20Sopenharmony_ci bnx2x_wait_for_link(bp, link_up, is_serdes); 30988c2ecf20Sopenharmony_ci } 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci if (bnx2x_test_intr(bp) != 0) { 31018c2ecf20Sopenharmony_ci if (!IS_MF(bp)) 31028c2ecf20Sopenharmony_ci buf[5] = 1; 31038c2ecf20Sopenharmony_ci else 31048c2ecf20Sopenharmony_ci buf[1] = 1; 31058c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 31068c2ecf20Sopenharmony_ci } 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci if (link_up) { 31098c2ecf20Sopenharmony_ci cnt = 100; 31108c2ecf20Sopenharmony_ci while (bnx2x_link_test(bp, is_serdes) && --cnt) 31118c2ecf20Sopenharmony_ci msleep(20); 31128c2ecf20Sopenharmony_ci } 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci if (!cnt) { 31158c2ecf20Sopenharmony_ci if (!IS_MF(bp)) 31168c2ecf20Sopenharmony_ci buf[6] = 1; 31178c2ecf20Sopenharmony_ci else 31188c2ecf20Sopenharmony_ci buf[2] = 1; 31198c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 31208c2ecf20Sopenharmony_ci } 31218c2ecf20Sopenharmony_ci} 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci#define IS_PORT_STAT(i) (bnx2x_stats_arr[i].is_port_stat) 31248c2ecf20Sopenharmony_ci#define HIDE_PORT_STAT(bp) IS_VF(bp) 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci/* ethtool statistics are displayed for all regular ethernet queues and the 31278c2ecf20Sopenharmony_ci * fcoe L2 queue if not disabled 31288c2ecf20Sopenharmony_ci */ 31298c2ecf20Sopenharmony_cistatic int bnx2x_num_stat_queues(struct bnx2x *bp) 31308c2ecf20Sopenharmony_ci{ 31318c2ecf20Sopenharmony_ci return BNX2X_NUM_ETH_QUEUES(bp); 31328c2ecf20Sopenharmony_ci} 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_cistatic int bnx2x_get_sset_count(struct net_device *dev, int stringset) 31358c2ecf20Sopenharmony_ci{ 31368c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 31378c2ecf20Sopenharmony_ci int i, num_strings = 0; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci switch (stringset) { 31408c2ecf20Sopenharmony_ci case ETH_SS_STATS: 31418c2ecf20Sopenharmony_ci if (is_multi(bp)) { 31428c2ecf20Sopenharmony_ci num_strings = bnx2x_num_stat_queues(bp) * 31438c2ecf20Sopenharmony_ci BNX2X_NUM_Q_STATS; 31448c2ecf20Sopenharmony_ci } else 31458c2ecf20Sopenharmony_ci num_strings = 0; 31468c2ecf20Sopenharmony_ci if (HIDE_PORT_STAT(bp)) { 31478c2ecf20Sopenharmony_ci for (i = 0; i < BNX2X_NUM_STATS; i++) 31488c2ecf20Sopenharmony_ci if (!IS_PORT_STAT(i)) 31498c2ecf20Sopenharmony_ci num_strings++; 31508c2ecf20Sopenharmony_ci } else 31518c2ecf20Sopenharmony_ci num_strings += BNX2X_NUM_STATS; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci return num_strings; 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci case ETH_SS_TEST: 31568c2ecf20Sopenharmony_ci return BNX2X_NUM_TESTS(bp); 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 31598c2ecf20Sopenharmony_ci return BNX2X_PRI_FLAG_LEN; 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci default: 31628c2ecf20Sopenharmony_ci return -EINVAL; 31638c2ecf20Sopenharmony_ci } 31648c2ecf20Sopenharmony_ci} 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_cistatic u32 bnx2x_get_private_flags(struct net_device *dev) 31678c2ecf20Sopenharmony_ci{ 31688c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 31698c2ecf20Sopenharmony_ci u32 flags = 0; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci flags |= (!(bp->flags & NO_ISCSI_FLAG) ? 1 : 0) << BNX2X_PRI_FLAG_ISCSI; 31728c2ecf20Sopenharmony_ci flags |= (!(bp->flags & NO_FCOE_FLAG) ? 1 : 0) << BNX2X_PRI_FLAG_FCOE; 31738c2ecf20Sopenharmony_ci flags |= (!!IS_MF_STORAGE_ONLY(bp)) << BNX2X_PRI_FLAG_STORAGE; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci return flags; 31768c2ecf20Sopenharmony_ci} 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_cistatic void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 31798c2ecf20Sopenharmony_ci{ 31808c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 31818c2ecf20Sopenharmony_ci int i, j, k, start; 31828c2ecf20Sopenharmony_ci char queue_name[MAX_QUEUE_NAME_LEN+1]; 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci switch (stringset) { 31858c2ecf20Sopenharmony_ci case ETH_SS_STATS: 31868c2ecf20Sopenharmony_ci k = 0; 31878c2ecf20Sopenharmony_ci if (is_multi(bp)) { 31888c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 31898c2ecf20Sopenharmony_ci memset(queue_name, 0, sizeof(queue_name)); 31908c2ecf20Sopenharmony_ci snprintf(queue_name, sizeof(queue_name), 31918c2ecf20Sopenharmony_ci "%d", i); 31928c2ecf20Sopenharmony_ci for (j = 0; j < BNX2X_NUM_Q_STATS; j++) 31938c2ecf20Sopenharmony_ci snprintf(buf + (k + j)*ETH_GSTRING_LEN, 31948c2ecf20Sopenharmony_ci ETH_GSTRING_LEN, 31958c2ecf20Sopenharmony_ci bnx2x_q_stats_arr[j].string, 31968c2ecf20Sopenharmony_ci queue_name); 31978c2ecf20Sopenharmony_ci k += BNX2X_NUM_Q_STATS; 31988c2ecf20Sopenharmony_ci } 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { 32028c2ecf20Sopenharmony_ci if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i)) 32038c2ecf20Sopenharmony_ci continue; 32048c2ecf20Sopenharmony_ci strcpy(buf + (k + j)*ETH_GSTRING_LEN, 32058c2ecf20Sopenharmony_ci bnx2x_stats_arr[i].string); 32068c2ecf20Sopenharmony_ci j++; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci break; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci case ETH_SS_TEST: 32128c2ecf20Sopenharmony_ci /* First 4 tests cannot be done in MF mode */ 32138c2ecf20Sopenharmony_ci if (!IS_MF(bp)) 32148c2ecf20Sopenharmony_ci start = 0; 32158c2ecf20Sopenharmony_ci else 32168c2ecf20Sopenharmony_ci start = 4; 32178c2ecf20Sopenharmony_ci memcpy(buf, bnx2x_tests_str_arr + start, 32188c2ecf20Sopenharmony_ci ETH_GSTRING_LEN * BNX2X_NUM_TESTS(bp)); 32198c2ecf20Sopenharmony_ci break; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 32228c2ecf20Sopenharmony_ci memcpy(buf, bnx2x_private_arr, 32238c2ecf20Sopenharmony_ci ETH_GSTRING_LEN * BNX2X_PRI_FLAG_LEN); 32248c2ecf20Sopenharmony_ci break; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci} 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_cistatic void bnx2x_get_ethtool_stats(struct net_device *dev, 32298c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 32328c2ecf20Sopenharmony_ci u32 *hw_stats, *offset; 32338c2ecf20Sopenharmony_ci int i, j, k = 0; 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci if (is_multi(bp)) { 32368c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 32378c2ecf20Sopenharmony_ci hw_stats = (u32 *)&bp->fp_stats[i].eth_q_stats; 32388c2ecf20Sopenharmony_ci for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { 32398c2ecf20Sopenharmony_ci if (bnx2x_q_stats_arr[j].size == 0) { 32408c2ecf20Sopenharmony_ci /* skip this counter */ 32418c2ecf20Sopenharmony_ci buf[k + j] = 0; 32428c2ecf20Sopenharmony_ci continue; 32438c2ecf20Sopenharmony_ci } 32448c2ecf20Sopenharmony_ci offset = (hw_stats + 32458c2ecf20Sopenharmony_ci bnx2x_q_stats_arr[j].offset); 32468c2ecf20Sopenharmony_ci if (bnx2x_q_stats_arr[j].size == 4) { 32478c2ecf20Sopenharmony_ci /* 4-byte counter */ 32488c2ecf20Sopenharmony_ci buf[k + j] = (u64) *offset; 32498c2ecf20Sopenharmony_ci continue; 32508c2ecf20Sopenharmony_ci } 32518c2ecf20Sopenharmony_ci /* 8-byte counter */ 32528c2ecf20Sopenharmony_ci buf[k + j] = HILO_U64(*offset, *(offset + 1)); 32538c2ecf20Sopenharmony_ci } 32548c2ecf20Sopenharmony_ci k += BNX2X_NUM_Q_STATS; 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci } 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci hw_stats = (u32 *)&bp->eth_stats; 32598c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { 32608c2ecf20Sopenharmony_ci if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i)) 32618c2ecf20Sopenharmony_ci continue; 32628c2ecf20Sopenharmony_ci if (bnx2x_stats_arr[i].size == 0) { 32638c2ecf20Sopenharmony_ci /* skip this counter */ 32648c2ecf20Sopenharmony_ci buf[k + j] = 0; 32658c2ecf20Sopenharmony_ci j++; 32668c2ecf20Sopenharmony_ci continue; 32678c2ecf20Sopenharmony_ci } 32688c2ecf20Sopenharmony_ci offset = (hw_stats + bnx2x_stats_arr[i].offset); 32698c2ecf20Sopenharmony_ci if (bnx2x_stats_arr[i].size == 4) { 32708c2ecf20Sopenharmony_ci /* 4-byte counter */ 32718c2ecf20Sopenharmony_ci buf[k + j] = (u64) *offset; 32728c2ecf20Sopenharmony_ci j++; 32738c2ecf20Sopenharmony_ci continue; 32748c2ecf20Sopenharmony_ci } 32758c2ecf20Sopenharmony_ci /* 8-byte counter */ 32768c2ecf20Sopenharmony_ci buf[k + j] = HILO_U64(*offset, *(offset + 1)); 32778c2ecf20Sopenharmony_ci j++; 32788c2ecf20Sopenharmony_ci } 32798c2ecf20Sopenharmony_ci} 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_cistatic int bnx2x_set_phys_id(struct net_device *dev, 32828c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 32838c2ecf20Sopenharmony_ci{ 32848c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci if (!bnx2x_is_nvm_accessible(bp)) { 32878c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, 32888c2ecf20Sopenharmony_ci "cannot access eeprom when the interface is down\n"); 32898c2ecf20Sopenharmony_ci return -EAGAIN; 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci switch (state) { 32938c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 32948c2ecf20Sopenharmony_ci return 1; /* cycle on/off once per second */ 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci case ETHTOOL_ID_ON: 32978c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 32988c2ecf20Sopenharmony_ci bnx2x_set_led(&bp->link_params, &bp->link_vars, 32998c2ecf20Sopenharmony_ci LED_MODE_ON, SPEED_1000); 33008c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 33018c2ecf20Sopenharmony_ci break; 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci case ETHTOOL_ID_OFF: 33048c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 33058c2ecf20Sopenharmony_ci bnx2x_set_led(&bp->link_params, &bp->link_vars, 33068c2ecf20Sopenharmony_ci LED_MODE_FRONT_PANEL_OFF, 0); 33078c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 33088c2ecf20Sopenharmony_ci break; 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 33118c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 33128c2ecf20Sopenharmony_ci bnx2x_set_led(&bp->link_params, &bp->link_vars, 33138c2ecf20Sopenharmony_ci LED_MODE_OPER, 33148c2ecf20Sopenharmony_ci bp->link_vars.line_speed); 33158c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 33168c2ecf20Sopenharmony_ci } 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci return 0; 33198c2ecf20Sopenharmony_ci} 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_cistatic int bnx2x_get_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) 33228c2ecf20Sopenharmony_ci{ 33238c2ecf20Sopenharmony_ci switch (info->flow_type) { 33248c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 33258c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 33268c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 33278c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 33288c2ecf20Sopenharmony_ci break; 33298c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 33308c2ecf20Sopenharmony_ci if (bp->rss_conf_obj.udp_rss_v4) 33318c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 33328c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 33338c2ecf20Sopenharmony_ci else 33348c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 33358c2ecf20Sopenharmony_ci break; 33368c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 33378c2ecf20Sopenharmony_ci if (bp->rss_conf_obj.udp_rss_v6) 33388c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 33398c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 33408c2ecf20Sopenharmony_ci else 33418c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 33428c2ecf20Sopenharmony_ci break; 33438c2ecf20Sopenharmony_ci case IPV4_FLOW: 33448c2ecf20Sopenharmony_ci case IPV6_FLOW: 33458c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 33468c2ecf20Sopenharmony_ci break; 33478c2ecf20Sopenharmony_ci default: 33488c2ecf20Sopenharmony_ci info->data = 0; 33498c2ecf20Sopenharmony_ci break; 33508c2ecf20Sopenharmony_ci } 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci return 0; 33538c2ecf20Sopenharmony_ci} 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_cistatic int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 33568c2ecf20Sopenharmony_ci u32 *rules __always_unused) 33578c2ecf20Sopenharmony_ci{ 33588c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci switch (info->cmd) { 33618c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 33628c2ecf20Sopenharmony_ci info->data = BNX2X_NUM_ETH_QUEUES(bp); 33638c2ecf20Sopenharmony_ci return 0; 33648c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: 33658c2ecf20Sopenharmony_ci return bnx2x_get_rss_flags(bp, info); 33668c2ecf20Sopenharmony_ci default: 33678c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n"); 33688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 33698c2ecf20Sopenharmony_ci } 33708c2ecf20Sopenharmony_ci} 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_cistatic int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) 33738c2ecf20Sopenharmony_ci{ 33748c2ecf20Sopenharmony_ci int udp_rss_requested; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 33778c2ecf20Sopenharmony_ci "Set rss flags command parameters: flow type = %d, data = %llu\n", 33788c2ecf20Sopenharmony_ci info->flow_type, info->data); 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci switch (info->flow_type) { 33818c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 33828c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 33838c2ecf20Sopenharmony_ci /* For TCP only 4-tupple hash is supported */ 33848c2ecf20Sopenharmony_ci if (info->data ^ (RXH_IP_SRC | RXH_IP_DST | 33858c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) { 33868c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 33878c2ecf20Sopenharmony_ci "Command parameters not supported\n"); 33888c2ecf20Sopenharmony_ci return -EINVAL; 33898c2ecf20Sopenharmony_ci } 33908c2ecf20Sopenharmony_ci return 0; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 33938c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 33948c2ecf20Sopenharmony_ci /* For UDP either 2-tupple hash or 4-tupple hash is supported */ 33958c2ecf20Sopenharmony_ci if (info->data == (RXH_IP_SRC | RXH_IP_DST | 33968c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3)) 33978c2ecf20Sopenharmony_ci udp_rss_requested = 1; 33988c2ecf20Sopenharmony_ci else if (info->data == (RXH_IP_SRC | RXH_IP_DST)) 33998c2ecf20Sopenharmony_ci udp_rss_requested = 0; 34008c2ecf20Sopenharmony_ci else 34018c2ecf20Sopenharmony_ci return -EINVAL; 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci if (CHIP_IS_E1x(bp) && udp_rss_requested) { 34048c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 34058c2ecf20Sopenharmony_ci "57710, 57711 boards don't support RSS according to UDP 4-tuple\n"); 34068c2ecf20Sopenharmony_ci return -EINVAL; 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci if ((info->flow_type == UDP_V4_FLOW) && 34108c2ecf20Sopenharmony_ci (bp->rss_conf_obj.udp_rss_v4 != udp_rss_requested)) { 34118c2ecf20Sopenharmony_ci bp->rss_conf_obj.udp_rss_v4 = udp_rss_requested; 34128c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 34138c2ecf20Sopenharmony_ci "rss re-configured, UDP 4-tupple %s\n", 34148c2ecf20Sopenharmony_ci udp_rss_requested ? "enabled" : "disabled"); 34158c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) 34168c2ecf20Sopenharmony_ci return bnx2x_rss(bp, &bp->rss_conf_obj, false, 34178c2ecf20Sopenharmony_ci true); 34188c2ecf20Sopenharmony_ci } else if ((info->flow_type == UDP_V6_FLOW) && 34198c2ecf20Sopenharmony_ci (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { 34208c2ecf20Sopenharmony_ci bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; 34218c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 34228c2ecf20Sopenharmony_ci "rss re-configured, UDP 4-tupple %s\n", 34238c2ecf20Sopenharmony_ci udp_rss_requested ? "enabled" : "disabled"); 34248c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) 34258c2ecf20Sopenharmony_ci return bnx2x_rss(bp, &bp->rss_conf_obj, false, 34268c2ecf20Sopenharmony_ci true); 34278c2ecf20Sopenharmony_ci } 34288c2ecf20Sopenharmony_ci return 0; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci case IPV4_FLOW: 34318c2ecf20Sopenharmony_ci case IPV6_FLOW: 34328c2ecf20Sopenharmony_ci /* For IP only 2-tupple hash is supported */ 34338c2ecf20Sopenharmony_ci if (info->data ^ (RXH_IP_SRC | RXH_IP_DST)) { 34348c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 34358c2ecf20Sopenharmony_ci "Command parameters not supported\n"); 34368c2ecf20Sopenharmony_ci return -EINVAL; 34378c2ecf20Sopenharmony_ci } 34388c2ecf20Sopenharmony_ci return 0; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 34418c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 34428c2ecf20Sopenharmony_ci case AH_V4_FLOW: 34438c2ecf20Sopenharmony_ci case ESP_V4_FLOW: 34448c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 34458c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 34468c2ecf20Sopenharmony_ci case AH_V6_FLOW: 34478c2ecf20Sopenharmony_ci case ESP_V6_FLOW: 34488c2ecf20Sopenharmony_ci case IP_USER_FLOW: 34498c2ecf20Sopenharmony_ci case ETHER_FLOW: 34508c2ecf20Sopenharmony_ci /* RSS is not supported for these protocols */ 34518c2ecf20Sopenharmony_ci if (info->data) { 34528c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 34538c2ecf20Sopenharmony_ci "Command parameters not supported\n"); 34548c2ecf20Sopenharmony_ci return -EINVAL; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci return 0; 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci default: 34598c2ecf20Sopenharmony_ci return -EINVAL; 34608c2ecf20Sopenharmony_ci } 34618c2ecf20Sopenharmony_ci} 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_cistatic int bnx2x_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info) 34648c2ecf20Sopenharmony_ci{ 34658c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci switch (info->cmd) { 34688c2ecf20Sopenharmony_ci case ETHTOOL_SRXFH: 34698c2ecf20Sopenharmony_ci return bnx2x_set_rss_flags(bp, info); 34708c2ecf20Sopenharmony_ci default: 34718c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "Command parameters not supported\n"); 34728c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34738c2ecf20Sopenharmony_ci } 34748c2ecf20Sopenharmony_ci} 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_cistatic u32 bnx2x_get_rxfh_indir_size(struct net_device *dev) 34778c2ecf20Sopenharmony_ci{ 34788c2ecf20Sopenharmony_ci return T_ETH_INDIRECTION_TABLE_SIZE; 34798c2ecf20Sopenharmony_ci} 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_cistatic int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, 34828c2ecf20Sopenharmony_ci u8 *hfunc) 34838c2ecf20Sopenharmony_ci{ 34848c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 34858c2ecf20Sopenharmony_ci u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; 34868c2ecf20Sopenharmony_ci size_t i; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci if (hfunc) 34898c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 34908c2ecf20Sopenharmony_ci if (!indir) 34918c2ecf20Sopenharmony_ci return 0; 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci /* Get the current configuration of the RSS indirection table */ 34948c2ecf20Sopenharmony_ci bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table); 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci /* 34978c2ecf20Sopenharmony_ci * We can't use a memcpy() as an internal storage of an 34988c2ecf20Sopenharmony_ci * indirection table is a u8 array while indir->ring_index 34998c2ecf20Sopenharmony_ci * points to an array of u32. 35008c2ecf20Sopenharmony_ci * 35018c2ecf20Sopenharmony_ci * Indirection table contains the FW Client IDs, so we need to 35028c2ecf20Sopenharmony_ci * align the returned table to the Client ID of the leading RSS 35038c2ecf20Sopenharmony_ci * queue. 35048c2ecf20Sopenharmony_ci */ 35058c2ecf20Sopenharmony_ci for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) 35068c2ecf20Sopenharmony_ci indir[i] = ind_table[i] - bp->fp->cl_id; 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci return 0; 35098c2ecf20Sopenharmony_ci} 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_cistatic int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, 35128c2ecf20Sopenharmony_ci const u8 *key, const u8 hfunc) 35138c2ecf20Sopenharmony_ci{ 35148c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 35158c2ecf20Sopenharmony_ci size_t i; 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci /* We require at least one supported parameter to be changed and no 35188c2ecf20Sopenharmony_ci * change in any of the unsupported parameters 35198c2ecf20Sopenharmony_ci */ 35208c2ecf20Sopenharmony_ci if (key || 35218c2ecf20Sopenharmony_ci (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) 35228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci if (!indir) 35258c2ecf20Sopenharmony_ci return 0; 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { 35288c2ecf20Sopenharmony_ci /* 35298c2ecf20Sopenharmony_ci * The same as in bnx2x_get_rxfh: we can't use a memcpy() 35308c2ecf20Sopenharmony_ci * as an internal storage of an indirection table is a u8 array 35318c2ecf20Sopenharmony_ci * while indir->ring_index points to an array of u32. 35328c2ecf20Sopenharmony_ci * 35338c2ecf20Sopenharmony_ci * Indirection table contains the FW Client IDs, so we need to 35348c2ecf20Sopenharmony_ci * align the received table to the Client ID of the leading RSS 35358c2ecf20Sopenharmony_ci * queue 35368c2ecf20Sopenharmony_ci */ 35378c2ecf20Sopenharmony_ci bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id; 35388c2ecf20Sopenharmony_ci } 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) 35418c2ecf20Sopenharmony_ci return bnx2x_config_rss_eth(bp, false); 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci return 0; 35448c2ecf20Sopenharmony_ci} 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci/** 35478c2ecf20Sopenharmony_ci * bnx2x_get_channels - gets the number of RSS queues. 35488c2ecf20Sopenharmony_ci * 35498c2ecf20Sopenharmony_ci * @dev: net device 35508c2ecf20Sopenharmony_ci * @channels: returns the number of max / current queues 35518c2ecf20Sopenharmony_ci */ 35528c2ecf20Sopenharmony_cistatic void bnx2x_get_channels(struct net_device *dev, 35538c2ecf20Sopenharmony_ci struct ethtool_channels *channels) 35548c2ecf20Sopenharmony_ci{ 35558c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci channels->max_combined = BNX2X_MAX_RSS_COUNT(bp); 35588c2ecf20Sopenharmony_ci channels->combined_count = BNX2X_NUM_ETH_QUEUES(bp); 35598c2ecf20Sopenharmony_ci} 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci/** 35628c2ecf20Sopenharmony_ci * bnx2x_change_num_queues - change the number of RSS queues. 35638c2ecf20Sopenharmony_ci * 35648c2ecf20Sopenharmony_ci * @bp: bnx2x private structure 35658c2ecf20Sopenharmony_ci * @num_rss: rss count 35668c2ecf20Sopenharmony_ci * 35678c2ecf20Sopenharmony_ci * Re-configure interrupt mode to get the new number of MSI-X 35688c2ecf20Sopenharmony_ci * vectors and re-add NAPI objects. 35698c2ecf20Sopenharmony_ci */ 35708c2ecf20Sopenharmony_cistatic void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss) 35718c2ecf20Sopenharmony_ci{ 35728c2ecf20Sopenharmony_ci bnx2x_disable_msi(bp); 35738c2ecf20Sopenharmony_ci bp->num_ethernet_queues = num_rss; 35748c2ecf20Sopenharmony_ci bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; 35758c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("set number of queues to %d\n", bp->num_queues); 35768c2ecf20Sopenharmony_ci bnx2x_set_int_mode(bp); 35778c2ecf20Sopenharmony_ci} 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci/** 35808c2ecf20Sopenharmony_ci * bnx2x_set_channels - sets the number of RSS queues. 35818c2ecf20Sopenharmony_ci * 35828c2ecf20Sopenharmony_ci * @dev: net device 35838c2ecf20Sopenharmony_ci * @channels: includes the number of queues requested 35848c2ecf20Sopenharmony_ci */ 35858c2ecf20Sopenharmony_cistatic int bnx2x_set_channels(struct net_device *dev, 35868c2ecf20Sopenharmony_ci struct ethtool_channels *channels) 35878c2ecf20Sopenharmony_ci{ 35888c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, 35918c2ecf20Sopenharmony_ci "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n", 35928c2ecf20Sopenharmony_ci channels->rx_count, channels->tx_count, channels->other_count, 35938c2ecf20Sopenharmony_ci channels->combined_count); 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci if (pci_num_vf(bp->pdev)) { 35968c2ecf20Sopenharmony_ci DP(BNX2X_MSG_IOV, "VFs are enabled, can not set channels\n"); 35978c2ecf20Sopenharmony_ci return -EPERM; 35988c2ecf20Sopenharmony_ci } 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_ci /* We don't support separate rx / tx channels. 36018c2ecf20Sopenharmony_ci * We don't allow setting 'other' channels. 36028c2ecf20Sopenharmony_ci */ 36038c2ecf20Sopenharmony_ci if (channels->rx_count || channels->tx_count || channels->other_count 36048c2ecf20Sopenharmony_ci || (channels->combined_count == 0) || 36058c2ecf20Sopenharmony_ci (channels->combined_count > BNX2X_MAX_RSS_COUNT(bp))) { 36068c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "command parameters not supported\n"); 36078c2ecf20Sopenharmony_ci return -EINVAL; 36088c2ecf20Sopenharmony_ci } 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci /* Check if there was a change in the active parameters */ 36118c2ecf20Sopenharmony_ci if (channels->combined_count == BNX2X_NUM_ETH_QUEUES(bp)) { 36128c2ecf20Sopenharmony_ci DP(BNX2X_MSG_ETHTOOL, "No change in active parameters\n"); 36138c2ecf20Sopenharmony_ci return 0; 36148c2ecf20Sopenharmony_ci } 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci /* Set the requested number of queues in bp context. 36178c2ecf20Sopenharmony_ci * Note that the actual number of queues created during load may be 36188c2ecf20Sopenharmony_ci * less than requested if memory is low. 36198c2ecf20Sopenharmony_ci */ 36208c2ecf20Sopenharmony_ci if (unlikely(!netif_running(dev))) { 36218c2ecf20Sopenharmony_ci bnx2x_change_num_queues(bp, channels->combined_count); 36228c2ecf20Sopenharmony_ci return 0; 36238c2ecf20Sopenharmony_ci } 36248c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_NORMAL, true); 36258c2ecf20Sopenharmony_ci bnx2x_change_num_queues(bp, channels->combined_count); 36268c2ecf20Sopenharmony_ci return bnx2x_nic_load(bp, LOAD_NORMAL); 36278c2ecf20Sopenharmony_ci} 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_cistatic int bnx2x_get_ts_info(struct net_device *dev, 36308c2ecf20Sopenharmony_ci struct ethtool_ts_info *info) 36318c2ecf20Sopenharmony_ci{ 36328c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_ci if (bp->flags & PTP_SUPPORTED) { 36358c2ecf20Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 36368c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 36378c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 36388c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 36398c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 36408c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci if (bp->ptp_clock) 36438c2ecf20Sopenharmony_ci info->phc_index = ptp_clock_index(bp->ptp_clock); 36448c2ecf20Sopenharmony_ci else 36458c2ecf20Sopenharmony_ci info->phc_index = -1; 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 36488c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | 36498c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | 36508c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci info->tx_types = (1 << HWTSTAMP_TX_OFF)|(1 << HWTSTAMP_TX_ON); 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci return 0; 36558c2ecf20Sopenharmony_ci } 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci return ethtool_op_get_ts_info(dev, info); 36588c2ecf20Sopenharmony_ci} 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_cistatic const struct ethtool_ops bnx2x_ethtool_ops = { 36618c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 36628c2ecf20Sopenharmony_ci .get_drvinfo = bnx2x_get_drvinfo, 36638c2ecf20Sopenharmony_ci .get_regs_len = bnx2x_get_regs_len, 36648c2ecf20Sopenharmony_ci .get_regs = bnx2x_get_regs, 36658c2ecf20Sopenharmony_ci .get_dump_flag = bnx2x_get_dump_flag, 36668c2ecf20Sopenharmony_ci .get_dump_data = bnx2x_get_dump_data, 36678c2ecf20Sopenharmony_ci .set_dump = bnx2x_set_dump, 36688c2ecf20Sopenharmony_ci .get_wol = bnx2x_get_wol, 36698c2ecf20Sopenharmony_ci .set_wol = bnx2x_set_wol, 36708c2ecf20Sopenharmony_ci .get_msglevel = bnx2x_get_msglevel, 36718c2ecf20Sopenharmony_ci .set_msglevel = bnx2x_set_msglevel, 36728c2ecf20Sopenharmony_ci .nway_reset = bnx2x_nway_reset, 36738c2ecf20Sopenharmony_ci .get_link = bnx2x_get_link, 36748c2ecf20Sopenharmony_ci .get_eeprom_len = bnx2x_get_eeprom_len, 36758c2ecf20Sopenharmony_ci .get_eeprom = bnx2x_get_eeprom, 36768c2ecf20Sopenharmony_ci .set_eeprom = bnx2x_set_eeprom, 36778c2ecf20Sopenharmony_ci .get_coalesce = bnx2x_get_coalesce, 36788c2ecf20Sopenharmony_ci .set_coalesce = bnx2x_set_coalesce, 36798c2ecf20Sopenharmony_ci .get_ringparam = bnx2x_get_ringparam, 36808c2ecf20Sopenharmony_ci .set_ringparam = bnx2x_set_ringparam, 36818c2ecf20Sopenharmony_ci .get_pauseparam = bnx2x_get_pauseparam, 36828c2ecf20Sopenharmony_ci .set_pauseparam = bnx2x_set_pauseparam, 36838c2ecf20Sopenharmony_ci .self_test = bnx2x_self_test, 36848c2ecf20Sopenharmony_ci .get_sset_count = bnx2x_get_sset_count, 36858c2ecf20Sopenharmony_ci .get_priv_flags = bnx2x_get_private_flags, 36868c2ecf20Sopenharmony_ci .get_strings = bnx2x_get_strings, 36878c2ecf20Sopenharmony_ci .set_phys_id = bnx2x_set_phys_id, 36888c2ecf20Sopenharmony_ci .get_ethtool_stats = bnx2x_get_ethtool_stats, 36898c2ecf20Sopenharmony_ci .get_rxnfc = bnx2x_get_rxnfc, 36908c2ecf20Sopenharmony_ci .set_rxnfc = bnx2x_set_rxnfc, 36918c2ecf20Sopenharmony_ci .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, 36928c2ecf20Sopenharmony_ci .get_rxfh = bnx2x_get_rxfh, 36938c2ecf20Sopenharmony_ci .set_rxfh = bnx2x_set_rxfh, 36948c2ecf20Sopenharmony_ci .get_channels = bnx2x_get_channels, 36958c2ecf20Sopenharmony_ci .set_channels = bnx2x_set_channels, 36968c2ecf20Sopenharmony_ci .get_module_info = bnx2x_get_module_info, 36978c2ecf20Sopenharmony_ci .get_module_eeprom = bnx2x_get_module_eeprom, 36988c2ecf20Sopenharmony_ci .get_eee = bnx2x_get_eee, 36998c2ecf20Sopenharmony_ci .set_eee = bnx2x_set_eee, 37008c2ecf20Sopenharmony_ci .get_ts_info = bnx2x_get_ts_info, 37018c2ecf20Sopenharmony_ci .get_link_ksettings = bnx2x_get_link_ksettings, 37028c2ecf20Sopenharmony_ci .set_link_ksettings = bnx2x_set_link_ksettings, 37038c2ecf20Sopenharmony_ci}; 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_cistatic const struct ethtool_ops bnx2x_vf_ethtool_ops = { 37068c2ecf20Sopenharmony_ci .get_drvinfo = bnx2x_get_drvinfo, 37078c2ecf20Sopenharmony_ci .get_msglevel = bnx2x_get_msglevel, 37088c2ecf20Sopenharmony_ci .set_msglevel = bnx2x_set_msglevel, 37098c2ecf20Sopenharmony_ci .get_link = bnx2x_get_link, 37108c2ecf20Sopenharmony_ci .get_coalesce = bnx2x_get_coalesce, 37118c2ecf20Sopenharmony_ci .get_ringparam = bnx2x_get_ringparam, 37128c2ecf20Sopenharmony_ci .set_ringparam = bnx2x_set_ringparam, 37138c2ecf20Sopenharmony_ci .get_sset_count = bnx2x_get_sset_count, 37148c2ecf20Sopenharmony_ci .get_strings = bnx2x_get_strings, 37158c2ecf20Sopenharmony_ci .get_ethtool_stats = bnx2x_get_ethtool_stats, 37168c2ecf20Sopenharmony_ci .get_rxnfc = bnx2x_get_rxnfc, 37178c2ecf20Sopenharmony_ci .set_rxnfc = bnx2x_set_rxnfc, 37188c2ecf20Sopenharmony_ci .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size, 37198c2ecf20Sopenharmony_ci .get_rxfh = bnx2x_get_rxfh, 37208c2ecf20Sopenharmony_ci .set_rxfh = bnx2x_set_rxfh, 37218c2ecf20Sopenharmony_ci .get_channels = bnx2x_get_channels, 37228c2ecf20Sopenharmony_ci .set_channels = bnx2x_set_channels, 37238c2ecf20Sopenharmony_ci .get_link_ksettings = bnx2x_get_vf_link_ksettings, 37248c2ecf20Sopenharmony_ci}; 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_civoid bnx2x_set_ethtool_ops(struct bnx2x *bp, struct net_device *netdev) 37278c2ecf20Sopenharmony_ci{ 37288c2ecf20Sopenharmony_ci netdev->ethtool_ops = (IS_PF(bp)) ? 37298c2ecf20Sopenharmony_ci &bnx2x_ethtool_ops : &bnx2x_vf_ethtool_ops; 37308c2ecf20Sopenharmony_ci} 3731