18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic qlcnic NIC Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/pci.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 128c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "qlcnic.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct qlcnic_stats { 178c2ecf20Sopenharmony_ci char stat_string[ETH_GSTRING_LEN]; 188c2ecf20Sopenharmony_ci int sizeof_stat; 198c2ecf20Sopenharmony_ci int stat_offset; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define QLC_SIZEOF(m) sizeof_field(struct qlcnic_adapter, m) 238c2ecf20Sopenharmony_ci#define QLC_OFF(m) offsetof(struct qlcnic_adapter, m) 248c2ecf20Sopenharmony_cistatic const u32 qlcnic_fw_dump_level[] = { 258c2ecf20Sopenharmony_ci 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic const struct qlcnic_stats qlcnic_gstrings_stats[] = { 298c2ecf20Sopenharmony_ci {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)}, 308c2ecf20Sopenharmony_ci {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)}, 318c2ecf20Sopenharmony_ci {"xmit_called", QLC_SIZEOF(stats.xmitcalled), 328c2ecf20Sopenharmony_ci QLC_OFF(stats.xmitcalled)}, 338c2ecf20Sopenharmony_ci {"xmit_finished", QLC_SIZEOF(stats.xmitfinished), 348c2ecf20Sopenharmony_ci QLC_OFF(stats.xmitfinished)}, 358c2ecf20Sopenharmony_ci {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error), 368c2ecf20Sopenharmony_ci QLC_OFF(stats.tx_dma_map_error)}, 378c2ecf20Sopenharmony_ci {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)}, 388c2ecf20Sopenharmony_ci {"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)}, 398c2ecf20Sopenharmony_ci {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error), 408c2ecf20Sopenharmony_ci QLC_OFF(stats.rx_dma_map_error)}, 418c2ecf20Sopenharmony_ci {"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)}, 428c2ecf20Sopenharmony_ci {"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)}, 438c2ecf20Sopenharmony_ci {"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)}, 448c2ecf20Sopenharmony_ci {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)}, 458c2ecf20Sopenharmony_ci {"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)}, 468c2ecf20Sopenharmony_ci {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)}, 478c2ecf20Sopenharmony_ci {"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)}, 488c2ecf20Sopenharmony_ci {"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)}, 498c2ecf20Sopenharmony_ci {"encap_lso_frames", QLC_SIZEOF(stats.encap_lso_frames), 508c2ecf20Sopenharmony_ci QLC_OFF(stats.encap_lso_frames)}, 518c2ecf20Sopenharmony_ci {"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed), 528c2ecf20Sopenharmony_ci QLC_OFF(stats.encap_tx_csummed)}, 538c2ecf20Sopenharmony_ci {"encap_rx_csummed", QLC_SIZEOF(stats.encap_rx_csummed), 548c2ecf20Sopenharmony_ci QLC_OFF(stats.encap_rx_csummed)}, 558c2ecf20Sopenharmony_ci {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), 568c2ecf20Sopenharmony_ci QLC_OFF(stats.skb_alloc_failure)}, 578c2ecf20Sopenharmony_ci {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun), 588c2ecf20Sopenharmony_ci QLC_OFF(stats.mac_filter_limit_overrun)}, 598c2ecf20Sopenharmony_ci {"spurious intr", QLC_SIZEOF(stats.spurious_intr), 608c2ecf20Sopenharmony_ci QLC_OFF(stats.spurious_intr)}, 618c2ecf20Sopenharmony_ci {"mbx spurious intr", QLC_SIZEOF(stats.mbx_spurious_intr), 628c2ecf20Sopenharmony_ci QLC_OFF(stats.mbx_spurious_intr)}, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = { 668c2ecf20Sopenharmony_ci "tx unicast frames", 678c2ecf20Sopenharmony_ci "tx multicast frames", 688c2ecf20Sopenharmony_ci "tx broadcast frames", 698c2ecf20Sopenharmony_ci "tx dropped frames", 708c2ecf20Sopenharmony_ci "tx errors", 718c2ecf20Sopenharmony_ci "tx local frames", 728c2ecf20Sopenharmony_ci "tx numbytes", 738c2ecf20Sopenharmony_ci "rx unicast frames", 748c2ecf20Sopenharmony_ci "rx multicast frames", 758c2ecf20Sopenharmony_ci "rx broadcast frames", 768c2ecf20Sopenharmony_ci "rx dropped frames", 778c2ecf20Sopenharmony_ci "rx errors", 788c2ecf20Sopenharmony_ci "rx local frames", 798c2ecf20Sopenharmony_ci "rx numbytes", 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = { 838c2ecf20Sopenharmony_ci "ctx_tx_bytes", 848c2ecf20Sopenharmony_ci "ctx_tx_pkts", 858c2ecf20Sopenharmony_ci "ctx_tx_errors", 868c2ecf20Sopenharmony_ci "ctx_tx_dropped_pkts", 878c2ecf20Sopenharmony_ci "ctx_tx_num_buffers", 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = { 918c2ecf20Sopenharmony_ci "mac_tx_frames", 928c2ecf20Sopenharmony_ci "mac_tx_bytes", 938c2ecf20Sopenharmony_ci "mac_tx_mcast_pkts", 948c2ecf20Sopenharmony_ci "mac_tx_bcast_pkts", 958c2ecf20Sopenharmony_ci "mac_tx_pause_cnt", 968c2ecf20Sopenharmony_ci "mac_tx_ctrl_pkt", 978c2ecf20Sopenharmony_ci "mac_tx_lt_64b_pkts", 988c2ecf20Sopenharmony_ci "mac_tx_lt_127b_pkts", 998c2ecf20Sopenharmony_ci "mac_tx_lt_255b_pkts", 1008c2ecf20Sopenharmony_ci "mac_tx_lt_511b_pkts", 1018c2ecf20Sopenharmony_ci "mac_tx_lt_1023b_pkts", 1028c2ecf20Sopenharmony_ci "mac_tx_lt_1518b_pkts", 1038c2ecf20Sopenharmony_ci "mac_tx_gt_1518b_pkts", 1048c2ecf20Sopenharmony_ci "mac_rx_frames", 1058c2ecf20Sopenharmony_ci "mac_rx_bytes", 1068c2ecf20Sopenharmony_ci "mac_rx_mcast_pkts", 1078c2ecf20Sopenharmony_ci "mac_rx_bcast_pkts", 1088c2ecf20Sopenharmony_ci "mac_rx_pause_cnt", 1098c2ecf20Sopenharmony_ci "mac_rx_ctrl_pkt", 1108c2ecf20Sopenharmony_ci "mac_rx_lt_64b_pkts", 1118c2ecf20Sopenharmony_ci "mac_rx_lt_127b_pkts", 1128c2ecf20Sopenharmony_ci "mac_rx_lt_255b_pkts", 1138c2ecf20Sopenharmony_ci "mac_rx_lt_511b_pkts", 1148c2ecf20Sopenharmony_ci "mac_rx_lt_1023b_pkts", 1158c2ecf20Sopenharmony_ci "mac_rx_lt_1518b_pkts", 1168c2ecf20Sopenharmony_ci "mac_rx_gt_1518b_pkts", 1178c2ecf20Sopenharmony_ci "mac_rx_length_error", 1188c2ecf20Sopenharmony_ci "mac_rx_length_small", 1198c2ecf20Sopenharmony_ci "mac_rx_length_large", 1208c2ecf20Sopenharmony_ci "mac_rx_jabber", 1218c2ecf20Sopenharmony_ci "mac_rx_dropped", 1228c2ecf20Sopenharmony_ci "mac_crc_error", 1238c2ecf20Sopenharmony_ci "mac_align_error", 1248c2ecf20Sopenharmony_ci "eswitch_frames", 1258c2ecf20Sopenharmony_ci "eswitch_bytes", 1268c2ecf20Sopenharmony_ci "eswitch_multicast_frames", 1278c2ecf20Sopenharmony_ci "eswitch_broadcast_frames", 1288c2ecf20Sopenharmony_ci "eswitch_unicast_frames", 1298c2ecf20Sopenharmony_ci "eswitch_error_free_frames", 1308c2ecf20Sopenharmony_ci "eswitch_error_free_bytes", 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic const char qlcnic_tx_queue_stats_strings[][ETH_GSTRING_LEN] = { 1368c2ecf20Sopenharmony_ci "xmit_on", 1378c2ecf20Sopenharmony_ci "xmit_off", 1388c2ecf20Sopenharmony_ci "xmit_called", 1398c2ecf20Sopenharmony_ci "xmit_finished", 1408c2ecf20Sopenharmony_ci "tx_bytes", 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define QLCNIC_TX_STATS_LEN ARRAY_SIZE(qlcnic_tx_queue_stats_strings) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = { 1468c2ecf20Sopenharmony_ci "ctx_rx_bytes", 1478c2ecf20Sopenharmony_ci "ctx_rx_pkts", 1488c2ecf20Sopenharmony_ci "ctx_lro_pkt_cnt", 1498c2ecf20Sopenharmony_ci "ctx_ip_csum_error", 1508c2ecf20Sopenharmony_ci "ctx_rx_pkts_wo_ctx", 1518c2ecf20Sopenharmony_ci "ctx_rx_pkts_drop_wo_sds_on_card", 1528c2ecf20Sopenharmony_ci "ctx_rx_pkts_drop_wo_sds_on_host", 1538c2ecf20Sopenharmony_ci "ctx_rx_osized_pkts", 1548c2ecf20Sopenharmony_ci "ctx_rx_pkts_dropped_wo_rds", 1558c2ecf20Sopenharmony_ci "ctx_rx_unexpected_mcast_pkts", 1568c2ecf20Sopenharmony_ci "ctx_invalid_mac_address", 1578c2ecf20Sopenharmony_ci "ctx_rx_rds_ring_prim_attempted", 1588c2ecf20Sopenharmony_ci "ctx_rx_rds_ring_prim_success", 1598c2ecf20Sopenharmony_ci "ctx_num_lro_flows_added", 1608c2ecf20Sopenharmony_ci "ctx_num_lro_flows_removed", 1618c2ecf20Sopenharmony_ci "ctx_num_lro_flows_active", 1628c2ecf20Sopenharmony_ci "ctx_pkts_dropped_unknown", 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { 1668c2ecf20Sopenharmony_ci "Register_Test_on_offline", 1678c2ecf20Sopenharmony_ci "Link_Test_on_offline", 1688c2ecf20Sopenharmony_ci "Interrupt_Test_offline", 1698c2ecf20Sopenharmony_ci "Internal_Loopback_offline", 1708c2ecf20Sopenharmony_ci "External_Loopback_offline", 1718c2ecf20Sopenharmony_ci "EEPROM_Test_offline" 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic inline int qlcnic_82xx_statistics(struct qlcnic_adapter *adapter) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return ARRAY_SIZE(qlcnic_gstrings_stats) + 1798c2ecf20Sopenharmony_ci ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) + 1808c2ecf20Sopenharmony_ci QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic inline int qlcnic_83xx_statistics(struct qlcnic_adapter *adapter) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci return ARRAY_SIZE(qlcnic_gstrings_stats) + 1868c2ecf20Sopenharmony_ci ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) + 1878c2ecf20Sopenharmony_ci ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) + 1888c2ecf20Sopenharmony_ci ARRAY_SIZE(qlcnic_83xx_rx_stats_strings) + 1898c2ecf20Sopenharmony_ci QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci int len = -1; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) { 1978c2ecf20Sopenharmony_ci len = qlcnic_82xx_statistics(adapter); 1988c2ecf20Sopenharmony_ci if (adapter->flags & QLCNIC_ESWITCH_ENABLED) 1998c2ecf20Sopenharmony_ci len += ARRAY_SIZE(qlcnic_device_gstrings_stats); 2008c2ecf20Sopenharmony_ci } else if (qlcnic_83xx_check(adapter)) { 2018c2ecf20Sopenharmony_ci len = qlcnic_83xx_statistics(adapter); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return len; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define QLCNIC_TX_INTR_NOT_CONFIGURED 0X78563412 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define QLCNIC_MAX_EEPROM_LEN 1024 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic const u32 diag_registers[] = { 2128c2ecf20Sopenharmony_ci QLCNIC_CMDPEG_STATE, 2138c2ecf20Sopenharmony_ci QLCNIC_RCVPEG_STATE, 2148c2ecf20Sopenharmony_ci QLCNIC_FW_CAPABILITIES, 2158c2ecf20Sopenharmony_ci QLCNIC_CRB_DRV_ACTIVE, 2168c2ecf20Sopenharmony_ci QLCNIC_CRB_DEV_STATE, 2178c2ecf20Sopenharmony_ci QLCNIC_CRB_DRV_STATE, 2188c2ecf20Sopenharmony_ci QLCNIC_CRB_DRV_SCRATCH, 2198c2ecf20Sopenharmony_ci QLCNIC_CRB_DEV_PARTITION_INFO, 2208c2ecf20Sopenharmony_ci QLCNIC_CRB_DRV_IDC_VER, 2218c2ecf20Sopenharmony_ci QLCNIC_PEG_ALIVE_COUNTER, 2228c2ecf20Sopenharmony_ci QLCNIC_PEG_HALT_STATUS1, 2238c2ecf20Sopenharmony_ci QLCNIC_PEG_HALT_STATUS2, 2248c2ecf20Sopenharmony_ci -1 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic const u32 ext_diag_registers[] = { 2298c2ecf20Sopenharmony_ci CRB_XG_STATE_P3P, 2308c2ecf20Sopenharmony_ci ISR_INT_STATE_REG, 2318c2ecf20Sopenharmony_ci QLCNIC_CRB_PEG_NET_0+0x3c, 2328c2ecf20Sopenharmony_ci QLCNIC_CRB_PEG_NET_1+0x3c, 2338c2ecf20Sopenharmony_ci QLCNIC_CRB_PEG_NET_2+0x3c, 2348c2ecf20Sopenharmony_ci QLCNIC_CRB_PEG_NET_4+0x3c, 2358c2ecf20Sopenharmony_ci -1 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#define QLCNIC_MGMT_API_VERSION 3 2398c2ecf20Sopenharmony_ci#define QLCNIC_ETHTOOL_REGS_VER 4 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic inline int qlcnic_get_ring_regs_len(struct qlcnic_adapter *adapter) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci int ring_regs_cnt = (adapter->drv_tx_rings * 5) + 2448c2ecf20Sopenharmony_ci (adapter->max_rds_rings * 2) + 2458c2ecf20Sopenharmony_ci (adapter->drv_sds_rings * 3) + 5; 2468c2ecf20Sopenharmony_ci return ring_regs_cnt * sizeof(u32); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int qlcnic_get_regs_len(struct net_device *dev) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 2528c2ecf20Sopenharmony_ci u32 len; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 2558c2ecf20Sopenharmony_ci len = qlcnic_83xx_get_regs_len(adapter); 2568c2ecf20Sopenharmony_ci else 2578c2ecf20Sopenharmony_ci len = sizeof(ext_diag_registers) + sizeof(diag_registers); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci len += ((QLCNIC_DEV_INFO_SIZE + 2) * sizeof(u32)); 2608c2ecf20Sopenharmony_ci len += qlcnic_get_ring_regs_len(adapter); 2618c2ecf20Sopenharmony_ci return len; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int qlcnic_get_eeprom_len(struct net_device *dev) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci return QLCNIC_FLASH_TOTAL_SIZE; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void 2708c2ecf20Sopenharmony_ciqlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 2738c2ecf20Sopenharmony_ci u32 fw_major, fw_minor, fw_build; 2748c2ecf20Sopenharmony_ci fw_major = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MAJOR); 2758c2ecf20Sopenharmony_ci fw_minor = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_MINOR); 2768c2ecf20Sopenharmony_ci fw_build = QLC_SHARED_REG_RD32(adapter, QLCNIC_FW_VERSION_SUB); 2778c2ecf20Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 2788c2ecf20Sopenharmony_ci "%d.%d.%d", fw_major, fw_minor, fw_build); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 2818c2ecf20Sopenharmony_ci sizeof(drvinfo->bus_info)); 2828c2ecf20Sopenharmony_ci strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver)); 2838c2ecf20Sopenharmony_ci strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 2848c2ecf20Sopenharmony_ci sizeof(drvinfo->version)); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int qlcnic_82xx_get_link_ksettings(struct qlcnic_adapter *adapter, 2888c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *ecmd) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 2918c2ecf20Sopenharmony_ci u32 speed, reg; 2928c2ecf20Sopenharmony_ci int check_sfp_module = 0, err = 0; 2938c2ecf20Sopenharmony_ci u16 pcifn = ahw->pci_func; 2948c2ecf20Sopenharmony_ci u32 supported, advertising; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* read which mode */ 2978c2ecf20Sopenharmony_ci if (adapter->ahw->port_type == QLCNIC_GBE) { 2988c2ecf20Sopenharmony_ci supported = (SUPPORTED_10baseT_Half | 2998c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Full | 3008c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Half | 3018c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Full | 3028c2ecf20Sopenharmony_ci SUPPORTED_1000baseT_Half | 3038c2ecf20Sopenharmony_ci SUPPORTED_1000baseT_Full); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci advertising = (ADVERTISED_100baseT_Half | 3068c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Full | 3078c2ecf20Sopenharmony_ci ADVERTISED_1000baseT_Half | 3088c2ecf20Sopenharmony_ci ADVERTISED_1000baseT_Full); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ecmd->base.speed = adapter->ahw->link_speed; 3118c2ecf20Sopenharmony_ci ecmd->base.duplex = adapter->ahw->link_duplex; 3128c2ecf20Sopenharmony_ci ecmd->base.autoneg = adapter->ahw->link_autoneg; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci } else if (adapter->ahw->port_type == QLCNIC_XGBE) { 3158c2ecf20Sopenharmony_ci u32 val = 0; 3168c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (val == QLCNIC_PORT_MODE_802_3_AP) { 3198c2ecf20Sopenharmony_ci supported = SUPPORTED_1000baseT_Full; 3208c2ecf20Sopenharmony_ci advertising = ADVERTISED_1000baseT_Full; 3218c2ecf20Sopenharmony_ci } else { 3228c2ecf20Sopenharmony_ci supported = SUPPORTED_10000baseT_Full; 3238c2ecf20Sopenharmony_ci advertising = ADVERTISED_10000baseT_Full; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (netif_running(adapter->netdev) && ahw->has_link_events) { 3278c2ecf20Sopenharmony_ci if (ahw->linkup) { 3288c2ecf20Sopenharmony_ci reg = QLCRD32(adapter, 3298c2ecf20Sopenharmony_ci P3P_LINK_SPEED_REG(pcifn), &err); 3308c2ecf20Sopenharmony_ci speed = P3P_LINK_SPEED_VAL(pcifn, reg); 3318c2ecf20Sopenharmony_ci ahw->link_speed = speed * P3P_LINK_SPEED_MHZ; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ecmd->base.speed = ahw->link_speed; 3358c2ecf20Sopenharmony_ci ecmd->base.autoneg = ahw->link_autoneg; 3368c2ecf20Sopenharmony_ci ecmd->base.duplex = ahw->link_duplex; 3378c2ecf20Sopenharmony_ci goto skip; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ecmd->base.speed = SPEED_UNKNOWN; 3418c2ecf20Sopenharmony_ci ecmd->base.duplex = DUPLEX_UNKNOWN; 3428c2ecf20Sopenharmony_ci ecmd->base.autoneg = AUTONEG_DISABLE; 3438c2ecf20Sopenharmony_ci } else 3448c2ecf20Sopenharmony_ci return -EIO; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ciskip: 3478c2ecf20Sopenharmony_ci ecmd->base.phy_address = adapter->ahw->physical_port; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci switch (adapter->ahw->board_type) { 3508c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_REF_QG: 3518c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_4_GB: 3528c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_4_GB_MM: 3538c2ecf20Sopenharmony_ci supported |= SUPPORTED_Autoneg; 3548c2ecf20Sopenharmony_ci advertising |= ADVERTISED_Autoneg; 3558c2ecf20Sopenharmony_ci fallthrough; 3568c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_CX4: 3578c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_CX4_LP: 3588c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10000_BASE_T: 3598c2ecf20Sopenharmony_ci supported |= SUPPORTED_TP; 3608c2ecf20Sopenharmony_ci advertising |= ADVERTISED_TP; 3618c2ecf20Sopenharmony_ci ecmd->base.port = PORT_TP; 3628c2ecf20Sopenharmony_ci ecmd->base.autoneg = adapter->ahw->link_autoneg; 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_IMEZ: 3658c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_XG_LOM: 3668c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_HMEZ: 3678c2ecf20Sopenharmony_ci supported |= SUPPORTED_MII; 3688c2ecf20Sopenharmony_ci advertising |= ADVERTISED_MII; 3698c2ecf20Sopenharmony_ci ecmd->base.port = PORT_MII; 3708c2ecf20Sopenharmony_ci ecmd->base.autoneg = AUTONEG_DISABLE; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS: 3738c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_SFP_CT: 3748c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_SFP_QT: 3758c2ecf20Sopenharmony_ci advertising |= ADVERTISED_TP; 3768c2ecf20Sopenharmony_ci supported |= SUPPORTED_TP; 3778c2ecf20Sopenharmony_ci check_sfp_module = netif_running(adapter->netdev) && 3788c2ecf20Sopenharmony_ci ahw->has_link_events; 3798c2ecf20Sopenharmony_ci fallthrough; 3808c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_XFP: 3818c2ecf20Sopenharmony_ci supported |= SUPPORTED_FIBRE; 3828c2ecf20Sopenharmony_ci advertising |= ADVERTISED_FIBRE; 3838c2ecf20Sopenharmony_ci ecmd->base.port = PORT_FIBRE; 3848c2ecf20Sopenharmony_ci ecmd->base.autoneg = AUTONEG_DISABLE; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case QLCNIC_BRDTYPE_P3P_10G_TP: 3878c2ecf20Sopenharmony_ci if (adapter->ahw->port_type == QLCNIC_XGBE) { 3888c2ecf20Sopenharmony_ci ecmd->base.autoneg = AUTONEG_DISABLE; 3898c2ecf20Sopenharmony_ci supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); 3908c2ecf20Sopenharmony_ci advertising |= 3918c2ecf20Sopenharmony_ci (ADVERTISED_FIBRE | ADVERTISED_TP); 3928c2ecf20Sopenharmony_ci ecmd->base.port = PORT_FIBRE; 3938c2ecf20Sopenharmony_ci check_sfp_module = netif_running(adapter->netdev) && 3948c2ecf20Sopenharmony_ci ahw->has_link_events; 3958c2ecf20Sopenharmony_ci } else { 3968c2ecf20Sopenharmony_ci ecmd->base.autoneg = AUTONEG_ENABLE; 3978c2ecf20Sopenharmony_ci supported |= (SUPPORTED_TP | SUPPORTED_Autoneg); 3988c2ecf20Sopenharmony_ci advertising |= 3998c2ecf20Sopenharmony_ci (ADVERTISED_TP | ADVERTISED_Autoneg); 4008c2ecf20Sopenharmony_ci ecmd->base.port = PORT_TP; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci default: 4048c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unsupported board model %d\n", 4058c2ecf20Sopenharmony_ci adapter->ahw->board_type); 4068c2ecf20Sopenharmony_ci return -EIO; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (check_sfp_module) { 4108c2ecf20Sopenharmony_ci switch (adapter->ahw->module_type) { 4118c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_OPTICAL_UNKNOWN: 4128c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_OPTICAL_SRLR: 4138c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_OPTICAL_LRM: 4148c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_OPTICAL_SFP_1G: 4158c2ecf20Sopenharmony_ci ecmd->base.port = PORT_FIBRE; 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE: 4188c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN: 4198c2ecf20Sopenharmony_ci case LINKEVENT_MODULE_TWINAX: 4208c2ecf20Sopenharmony_ci ecmd->base.port = PORT_TP; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci default: 4238c2ecf20Sopenharmony_ci ecmd->base.port = PORT_OTHER; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported, 4288c2ecf20Sopenharmony_ci supported); 4298c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising, 4308c2ecf20Sopenharmony_ci advertising); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int qlcnic_get_link_ksettings(struct net_device *dev, 4368c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *ecmd) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 4418c2ecf20Sopenharmony_ci return qlcnic_82xx_get_link_ksettings(adapter, ecmd); 4428c2ecf20Sopenharmony_ci else if (qlcnic_83xx_check(adapter)) 4438c2ecf20Sopenharmony_ci return qlcnic_83xx_get_link_ksettings(adapter, ecmd); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return -EIO; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int qlcnic_set_port_config(struct qlcnic_adapter *adapter, 4508c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *ecmd) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci u32 ret = 0, config = 0; 4538c2ecf20Sopenharmony_ci /* read which mode */ 4548c2ecf20Sopenharmony_ci if (ecmd->base.duplex) 4558c2ecf20Sopenharmony_ci config |= 0x1; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (ecmd->base.autoneg) 4588c2ecf20Sopenharmony_ci config |= 0x2; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci switch (ecmd->base.speed) { 4618c2ecf20Sopenharmony_ci case SPEED_10: 4628c2ecf20Sopenharmony_ci config |= (0 << 8); 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci case SPEED_100: 4658c2ecf20Sopenharmony_ci config |= (1 << 8); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case SPEED_1000: 4688c2ecf20Sopenharmony_ci config |= (10 << 8); 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci default: 4718c2ecf20Sopenharmony_ci return -EIO; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci ret = qlcnic_fw_cmd_set_port(adapter, config); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (ret == QLCNIC_RCODE_NOT_SUPPORTED) 4778c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4788c2ecf20Sopenharmony_ci else if (ret) 4798c2ecf20Sopenharmony_ci return -EIO; 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int qlcnic_set_link_ksettings(struct net_device *dev, 4848c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *ecmd) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci u32 ret = 0; 4878c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 4908c2ecf20Sopenharmony_ci qlcnic_83xx_get_port_type(adapter); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (adapter->ahw->port_type != QLCNIC_GBE) 4938c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 4968c2ecf20Sopenharmony_ci ret = qlcnic_83xx_set_link_ksettings(adapter, ecmd); 4978c2ecf20Sopenharmony_ci else 4988c2ecf20Sopenharmony_ci ret = qlcnic_set_port_config(adapter, ecmd); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (!ret) 5018c2ecf20Sopenharmony_ci return ret; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci adapter->ahw->link_speed = ecmd->base.speed; 5048c2ecf20Sopenharmony_ci adapter->ahw->link_duplex = ecmd->base.duplex; 5058c2ecf20Sopenharmony_ci adapter->ahw->link_autoneg = ecmd->base.autoneg; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (!netif_running(dev)) 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci dev->netdev_ops->ndo_stop(dev); 5118c2ecf20Sopenharmony_ci return dev->netdev_ops->ndo_open(dev); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter, 5158c2ecf20Sopenharmony_ci u32 *regs_buff) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci int i, j = 0, err = 0; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++) 5208c2ecf20Sopenharmony_ci regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]); 5218c2ecf20Sopenharmony_ci j = 0; 5228c2ecf20Sopenharmony_ci while (ext_diag_registers[j] != -1) 5238c2ecf20Sopenharmony_ci regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++], 5248c2ecf20Sopenharmony_ci &err); 5258c2ecf20Sopenharmony_ci return i; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic void 5298c2ecf20Sopenharmony_ciqlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 5328c2ecf20Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 5338c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 5348c2ecf20Sopenharmony_ci struct qlcnic_host_rds_ring *rds_rings; 5358c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 5368c2ecf20Sopenharmony_ci u32 *regs_buff = p; 5378c2ecf20Sopenharmony_ci int ring, i = 0; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci memset(p, 0, qlcnic_get_regs_len(dev)); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) | 5428c2ecf20Sopenharmony_ci (adapter->ahw->revision_id << 16) | (adapter->pdev)->device; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff)); 5458c2ecf20Sopenharmony_ci regs_buff[1] = QLCNIC_MGMT_API_VERSION; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (adapter->ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) 5488c2ecf20Sopenharmony_ci regs_buff[2] = adapter->ahw->max_vnic_func; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 5518c2ecf20Sopenharmony_ci i = qlcnic_82xx_get_registers(adapter, regs_buff); 5528c2ecf20Sopenharmony_ci else 5538c2ecf20Sopenharmony_ci i = qlcnic_83xx_get_registers(adapter, regs_buff); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) 5568c2ecf20Sopenharmony_ci return; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* Marker btw regs and TX ring count */ 5598c2ecf20Sopenharmony_ci regs_buff[i++] = 0xFFEFCDAB; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci regs_buff[i++] = adapter->drv_tx_rings; /* No. of TX ring */ 5628c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 5638c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 5648c2ecf20Sopenharmony_ci regs_buff[i++] = le32_to_cpu(*(tx_ring->hw_consumer)); 5658c2ecf20Sopenharmony_ci regs_buff[i++] = tx_ring->sw_consumer; 5668c2ecf20Sopenharmony_ci regs_buff[i++] = readl(tx_ring->crb_cmd_producer); 5678c2ecf20Sopenharmony_ci regs_buff[i++] = tx_ring->producer; 5688c2ecf20Sopenharmony_ci if (tx_ring->crb_intr_mask) 5698c2ecf20Sopenharmony_ci regs_buff[i++] = readl(tx_ring->crb_intr_mask); 5708c2ecf20Sopenharmony_ci else 5718c2ecf20Sopenharmony_ci regs_buff[i++] = QLCNIC_TX_INTR_NOT_CONFIGURED; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci regs_buff[i++] = adapter->max_rds_rings; /* No. of RX ring */ 5758c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->max_rds_rings; ring++) { 5768c2ecf20Sopenharmony_ci rds_rings = &recv_ctx->rds_rings[ring]; 5778c2ecf20Sopenharmony_ci regs_buff[i++] = readl(rds_rings->crb_rcv_producer); 5788c2ecf20Sopenharmony_ci regs_buff[i++] = rds_rings->producer; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci regs_buff[i++] = adapter->drv_sds_rings; /* No. of SDS ring */ 5828c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_sds_rings; ring++) { 5838c2ecf20Sopenharmony_ci sds_ring = &(recv_ctx->sds_rings[ring]); 5848c2ecf20Sopenharmony_ci regs_buff[i++] = readl(sds_ring->crb_sts_consumer); 5858c2ecf20Sopenharmony_ci regs_buff[i++] = sds_ring->consumer; 5868c2ecf20Sopenharmony_ci regs_buff[i++] = readl(sds_ring->crb_intr_mask); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic u32 qlcnic_test_link(struct net_device *dev) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 5938c2ecf20Sopenharmony_ci int err = 0; 5948c2ecf20Sopenharmony_ci u32 val; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 5978c2ecf20Sopenharmony_ci val = qlcnic_83xx_test_link(adapter); 5988c2ecf20Sopenharmony_ci return (val & 1) ? 0 : 1; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err); 6018c2ecf20Sopenharmony_ci if (err == -EIO) 6028c2ecf20Sopenharmony_ci return err; 6038c2ecf20Sopenharmony_ci val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val); 6048c2ecf20Sopenharmony_ci return (val == XG_LINK_UP_P3P) ? 0 : 1; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int 6088c2ecf20Sopenharmony_ciqlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 6098c2ecf20Sopenharmony_ci u8 *bytes) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 6128c2ecf20Sopenharmony_ci int offset; 6138c2ecf20Sopenharmony_ci int ret = -1; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci if (eeprom->len == 0) 6188c2ecf20Sopenharmony_ci return -EINVAL; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci eeprom->magic = (adapter->pdev)->vendor | 6218c2ecf20Sopenharmony_ci ((adapter->pdev)->device << 16); 6228c2ecf20Sopenharmony_ci offset = eeprom->offset; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 6258c2ecf20Sopenharmony_ci ret = qlcnic_rom_fast_read_words(adapter, offset, bytes, 6268c2ecf20Sopenharmony_ci eeprom->len); 6278c2ecf20Sopenharmony_ci if (ret < 0) 6288c2ecf20Sopenharmony_ci return ret; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic void 6348c2ecf20Sopenharmony_ciqlcnic_get_ringparam(struct net_device *dev, 6358c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ring->rx_pending = adapter->num_rxd; 6408c2ecf20Sopenharmony_ci ring->rx_jumbo_pending = adapter->num_jumbo_rxd; 6418c2ecf20Sopenharmony_ci ring->tx_pending = adapter->num_txd; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci ring->rx_max_pending = adapter->max_rxd; 6448c2ecf20Sopenharmony_ci ring->rx_jumbo_max_pending = adapter->max_jumbo_rxd; 6458c2ecf20Sopenharmony_ci ring->tx_max_pending = MAX_CMD_DESCRIPTORS; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic u32 6498c2ecf20Sopenharmony_ciqlcnic_validate_ringparam(u32 val, u32 min, u32 max, char *r_name) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci u32 num_desc; 6528c2ecf20Sopenharmony_ci num_desc = max(val, min); 6538c2ecf20Sopenharmony_ci num_desc = min(num_desc, max); 6548c2ecf20Sopenharmony_ci num_desc = roundup_pow_of_two(num_desc); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (val != num_desc) { 6578c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n", 6588c2ecf20Sopenharmony_ci qlcnic_driver_name, r_name, num_desc, val); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci return num_desc; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic int 6658c2ecf20Sopenharmony_ciqlcnic_set_ringparam(struct net_device *dev, 6668c2ecf20Sopenharmony_ci struct ethtool_ringparam *ring) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 6698c2ecf20Sopenharmony_ci u16 num_rxd, num_jumbo_rxd, num_txd; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (ring->rx_mini_pending) 6728c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci num_rxd = qlcnic_validate_ringparam(ring->rx_pending, 6758c2ecf20Sopenharmony_ci MIN_RCV_DESCRIPTORS, adapter->max_rxd, "rx"); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci num_jumbo_rxd = qlcnic_validate_ringparam(ring->rx_jumbo_pending, 6788c2ecf20Sopenharmony_ci MIN_JUMBO_DESCRIPTORS, adapter->max_jumbo_rxd, 6798c2ecf20Sopenharmony_ci "rx jumbo"); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci num_txd = qlcnic_validate_ringparam(ring->tx_pending, 6828c2ecf20Sopenharmony_ci MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx"); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd && 6858c2ecf20Sopenharmony_ci num_jumbo_rxd == adapter->num_jumbo_rxd) 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci adapter->num_rxd = num_rxd; 6898c2ecf20Sopenharmony_ci adapter->num_jumbo_rxd = num_jumbo_rxd; 6908c2ecf20Sopenharmony_ci adapter->num_txd = num_txd; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci return qlcnic_reset_context(adapter); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int qlcnic_validate_ring_count(struct qlcnic_adapter *adapter, 6968c2ecf20Sopenharmony_ci u8 rx_ring, u8 tx_ring) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci if (rx_ring == 0 || tx_ring == 0) 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (rx_ring != 0) { 7028c2ecf20Sopenharmony_ci if (rx_ring > adapter->max_sds_rings) { 7038c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 7048c2ecf20Sopenharmony_ci "Invalid ring count, SDS ring count %d should not be greater than max %d driver sds rings.\n", 7058c2ecf20Sopenharmony_ci rx_ring, adapter->max_sds_rings); 7068c2ecf20Sopenharmony_ci return -EINVAL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (tx_ring != 0) { 7118c2ecf20Sopenharmony_ci if (tx_ring > adapter->max_tx_rings) { 7128c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 7138c2ecf20Sopenharmony_ci "Invalid ring count, Tx ring count %d should not be greater than max %d driver Tx rings.\n", 7148c2ecf20Sopenharmony_ci tx_ring, adapter->max_tx_rings); 7158c2ecf20Sopenharmony_ci return -EINVAL; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic void qlcnic_get_channels(struct net_device *dev, 7238c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci channel->max_rx = adapter->max_sds_rings; 7288c2ecf20Sopenharmony_ci channel->max_tx = adapter->max_tx_rings; 7298c2ecf20Sopenharmony_ci channel->rx_count = adapter->drv_sds_rings; 7308c2ecf20Sopenharmony_ci channel->tx_count = adapter->drv_tx_rings; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int qlcnic_set_channels(struct net_device *dev, 7348c2ecf20Sopenharmony_ci struct ethtool_channels *channel) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 7378c2ecf20Sopenharmony_ci int err; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { 7408c2ecf20Sopenharmony_ci netdev_err(dev, "No RSS/TSS support in non MSI-X mode\n"); 7418c2ecf20Sopenharmony_ci return -EINVAL; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (channel->other_count || channel->combined_count) 7458c2ecf20Sopenharmony_ci return -EINVAL; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci err = qlcnic_validate_ring_count(adapter, channel->rx_count, 7488c2ecf20Sopenharmony_ci channel->tx_count); 7498c2ecf20Sopenharmony_ci if (err) 7508c2ecf20Sopenharmony_ci return err; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (adapter->drv_sds_rings != channel->rx_count) { 7538c2ecf20Sopenharmony_ci err = qlcnic_validate_rings(adapter, channel->rx_count, 7548c2ecf20Sopenharmony_ci QLCNIC_RX_QUEUE); 7558c2ecf20Sopenharmony_ci if (err) { 7568c2ecf20Sopenharmony_ci netdev_err(dev, "Unable to configure %u SDS rings\n", 7578c2ecf20Sopenharmony_ci channel->rx_count); 7588c2ecf20Sopenharmony_ci return err; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci adapter->drv_rss_rings = channel->rx_count; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (adapter->drv_tx_rings != channel->tx_count) { 7648c2ecf20Sopenharmony_ci err = qlcnic_validate_rings(adapter, channel->tx_count, 7658c2ecf20Sopenharmony_ci QLCNIC_TX_QUEUE); 7668c2ecf20Sopenharmony_ci if (err) { 7678c2ecf20Sopenharmony_ci netdev_err(dev, "Unable to configure %u Tx rings\n", 7688c2ecf20Sopenharmony_ci channel->tx_count); 7698c2ecf20Sopenharmony_ci return err; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci adapter->drv_tss_rings = channel->tx_count; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci adapter->flags |= QLCNIC_TSS_RSS; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci err = qlcnic_setup_rings(adapter); 7778c2ecf20Sopenharmony_ci netdev_info(dev, "Allocated %d SDS rings and %d Tx rings\n", 7788c2ecf20Sopenharmony_ci adapter->drv_sds_rings, adapter->drv_tx_rings); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return err; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic void 7848c2ecf20Sopenharmony_ciqlcnic_get_pauseparam(struct net_device *netdev, 7858c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 7888c2ecf20Sopenharmony_ci int port = adapter->ahw->physical_port; 7898c2ecf20Sopenharmony_ci int err = 0; 7908c2ecf20Sopenharmony_ci __u32 val; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 7938c2ecf20Sopenharmony_ci qlcnic_83xx_get_pauseparam(adapter, pause); 7948c2ecf20Sopenharmony_ci return; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci if (adapter->ahw->port_type == QLCNIC_GBE) { 7978c2ecf20Sopenharmony_ci if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) 7988c2ecf20Sopenharmony_ci return; 7998c2ecf20Sopenharmony_ci /* get flow control settings */ 8008c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err); 8018c2ecf20Sopenharmony_ci if (err == -EIO) 8028c2ecf20Sopenharmony_ci return; 8038c2ecf20Sopenharmony_ci pause->rx_pause = qlcnic_gb_get_rx_flowctl(val); 8048c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err); 8058c2ecf20Sopenharmony_ci if (err == -EIO) 8068c2ecf20Sopenharmony_ci return; 8078c2ecf20Sopenharmony_ci switch (port) { 8088c2ecf20Sopenharmony_ci case 0: 8098c2ecf20Sopenharmony_ci pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val)); 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci case 1: 8128c2ecf20Sopenharmony_ci pause->tx_pause = !(qlcnic_gb_get_gb1_mask(val)); 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci case 2: 8158c2ecf20Sopenharmony_ci pause->tx_pause = !(qlcnic_gb_get_gb2_mask(val)); 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci case 3: 8188c2ecf20Sopenharmony_ci default: 8198c2ecf20Sopenharmony_ci pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val)); 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci } else if (adapter->ahw->port_type == QLCNIC_XGBE) { 8238c2ecf20Sopenharmony_ci if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) 8248c2ecf20Sopenharmony_ci return; 8258c2ecf20Sopenharmony_ci pause->rx_pause = 1; 8268c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err); 8278c2ecf20Sopenharmony_ci if (err == -EIO) 8288c2ecf20Sopenharmony_ci return; 8298c2ecf20Sopenharmony_ci if (port == 0) 8308c2ecf20Sopenharmony_ci pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val)); 8318c2ecf20Sopenharmony_ci else 8328c2ecf20Sopenharmony_ci pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val)); 8338c2ecf20Sopenharmony_ci } else { 8348c2ecf20Sopenharmony_ci dev_err(&netdev->dev, "Unknown board type: %x\n", 8358c2ecf20Sopenharmony_ci adapter->ahw->port_type); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic int 8408c2ecf20Sopenharmony_ciqlcnic_set_pauseparam(struct net_device *netdev, 8418c2ecf20Sopenharmony_ci struct ethtool_pauseparam *pause) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 8448c2ecf20Sopenharmony_ci int port = adapter->ahw->physical_port; 8458c2ecf20Sopenharmony_ci int err = 0; 8468c2ecf20Sopenharmony_ci __u32 val; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 8498c2ecf20Sopenharmony_ci return qlcnic_83xx_set_pauseparam(adapter, pause); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* read mode */ 8528c2ecf20Sopenharmony_ci if (adapter->ahw->port_type == QLCNIC_GBE) { 8538c2ecf20Sopenharmony_ci if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) 8548c2ecf20Sopenharmony_ci return -EIO; 8558c2ecf20Sopenharmony_ci /* set flow control */ 8568c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err); 8578c2ecf20Sopenharmony_ci if (err == -EIO) 8588c2ecf20Sopenharmony_ci return err; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (pause->rx_pause) 8618c2ecf20Sopenharmony_ci qlcnic_gb_rx_flowctl(val); 8628c2ecf20Sopenharmony_ci else 8638c2ecf20Sopenharmony_ci qlcnic_gb_unset_rx_flowctl(val); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), 8668c2ecf20Sopenharmony_ci val); 8678c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val); 8688c2ecf20Sopenharmony_ci /* set autoneg */ 8698c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err); 8708c2ecf20Sopenharmony_ci if (err == -EIO) 8718c2ecf20Sopenharmony_ci return err; 8728c2ecf20Sopenharmony_ci switch (port) { 8738c2ecf20Sopenharmony_ci case 0: 8748c2ecf20Sopenharmony_ci if (pause->tx_pause) 8758c2ecf20Sopenharmony_ci qlcnic_gb_unset_gb0_mask(val); 8768c2ecf20Sopenharmony_ci else 8778c2ecf20Sopenharmony_ci qlcnic_gb_set_gb0_mask(val); 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci case 1: 8808c2ecf20Sopenharmony_ci if (pause->tx_pause) 8818c2ecf20Sopenharmony_ci qlcnic_gb_unset_gb1_mask(val); 8828c2ecf20Sopenharmony_ci else 8838c2ecf20Sopenharmony_ci qlcnic_gb_set_gb1_mask(val); 8848c2ecf20Sopenharmony_ci break; 8858c2ecf20Sopenharmony_ci case 2: 8868c2ecf20Sopenharmony_ci if (pause->tx_pause) 8878c2ecf20Sopenharmony_ci qlcnic_gb_unset_gb2_mask(val); 8888c2ecf20Sopenharmony_ci else 8898c2ecf20Sopenharmony_ci qlcnic_gb_set_gb2_mask(val); 8908c2ecf20Sopenharmony_ci break; 8918c2ecf20Sopenharmony_ci case 3: 8928c2ecf20Sopenharmony_ci default: 8938c2ecf20Sopenharmony_ci if (pause->tx_pause) 8948c2ecf20Sopenharmony_ci qlcnic_gb_unset_gb3_mask(val); 8958c2ecf20Sopenharmony_ci else 8968c2ecf20Sopenharmony_ci qlcnic_gb_set_gb3_mask(val); 8978c2ecf20Sopenharmony_ci break; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); 9008c2ecf20Sopenharmony_ci } else if (adapter->ahw->port_type == QLCNIC_XGBE) { 9018c2ecf20Sopenharmony_ci if (!pause->rx_pause || pause->autoneg) 9028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) 9058c2ecf20Sopenharmony_ci return -EIO; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err); 9088c2ecf20Sopenharmony_ci if (err == -EIO) 9098c2ecf20Sopenharmony_ci return err; 9108c2ecf20Sopenharmony_ci if (port == 0) { 9118c2ecf20Sopenharmony_ci if (pause->tx_pause) 9128c2ecf20Sopenharmony_ci qlcnic_xg_unset_xg0_mask(val); 9138c2ecf20Sopenharmony_ci else 9148c2ecf20Sopenharmony_ci qlcnic_xg_set_xg0_mask(val); 9158c2ecf20Sopenharmony_ci } else { 9168c2ecf20Sopenharmony_ci if (pause->tx_pause) 9178c2ecf20Sopenharmony_ci qlcnic_xg_unset_xg1_mask(val); 9188c2ecf20Sopenharmony_ci else 9198c2ecf20Sopenharmony_ci qlcnic_xg_set_xg1_mask(val); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val); 9228c2ecf20Sopenharmony_ci } else { 9238c2ecf20Sopenharmony_ci dev_err(&netdev->dev, "Unknown board type: %x\n", 9248c2ecf20Sopenharmony_ci adapter->ahw->port_type); 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci return 0; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int qlcnic_reg_test(struct net_device *dev) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 9328c2ecf20Sopenharmony_ci u32 data_read; 9338c2ecf20Sopenharmony_ci int err = 0; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 9368c2ecf20Sopenharmony_ci return qlcnic_83xx_reg_test(adapter); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err); 9398c2ecf20Sopenharmony_ci if (err == -EIO) 9408c2ecf20Sopenharmony_ci return err; 9418c2ecf20Sopenharmony_ci if ((data_read & 0xffff) != adapter->pdev->vendor) 9428c2ecf20Sopenharmony_ci return 1; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int qlcnic_eeprom_test(struct net_device *dev) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (qlcnic_82xx_check(adapter)) 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci return qlcnic_83xx_flash_test(adapter); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic int qlcnic_get_sset_count(struct net_device *dev, int sset) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 9618c2ecf20Sopenharmony_ci switch (sset) { 9628c2ecf20Sopenharmony_ci case ETH_SS_TEST: 9638c2ecf20Sopenharmony_ci return QLCNIC_TEST_LEN; 9648c2ecf20Sopenharmony_ci case ETH_SS_STATS: 9658c2ecf20Sopenharmony_ci return qlcnic_dev_statistics_len(adapter); 9668c2ecf20Sopenharmony_ci default: 9678c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int qlcnic_irq_test(struct net_device *netdev) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 9748c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 9758c2ecf20Sopenharmony_ci struct qlcnic_cmd_args cmd; 9768c2ecf20Sopenharmony_ci int ret, drv_sds_rings = adapter->drv_sds_rings; 9778c2ecf20Sopenharmony_ci int drv_tx_rings = adapter->drv_tx_rings; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 9808c2ecf20Sopenharmony_ci return qlcnic_83xx_interrupt_test(netdev); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 9838c2ecf20Sopenharmony_ci return -EIO; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST); 9868c2ecf20Sopenharmony_ci if (ret) 9878c2ecf20Sopenharmony_ci goto clear_diag_irq; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci ahw->diag_cnt = 0; 9908c2ecf20Sopenharmony_ci ret = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST); 9918c2ecf20Sopenharmony_ci if (ret) 9928c2ecf20Sopenharmony_ci goto free_diag_res; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci cmd.req.arg[1] = ahw->pci_func; 9958c2ecf20Sopenharmony_ci ret = qlcnic_issue_cmd(adapter, &cmd); 9968c2ecf20Sopenharmony_ci if (ret) 9978c2ecf20Sopenharmony_ci goto done; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci usleep_range(1000, 12000); 10008c2ecf20Sopenharmony_ci ret = !ahw->diag_cnt; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cidone: 10038c2ecf20Sopenharmony_ci qlcnic_free_mbx_args(&cmd); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cifree_diag_res: 10068c2ecf20Sopenharmony_ci qlcnic_diag_free_res(netdev, drv_sds_rings); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ciclear_diag_irq: 10098c2ecf20Sopenharmony_ci adapter->drv_sds_rings = drv_sds_rings; 10108c2ecf20Sopenharmony_ci adapter->drv_tx_rings = drv_tx_rings; 10118c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci return ret; 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci#define QLCNIC_ILB_PKT_SIZE 64 10178c2ecf20Sopenharmony_ci#define QLCNIC_NUM_ILB_PKT 16 10188c2ecf20Sopenharmony_ci#define QLCNIC_ILB_MAX_RCV_LOOP 10 10198c2ecf20Sopenharmony_ci#define QLCNIC_LB_PKT_POLL_DELAY_MSEC 1 10208c2ecf20Sopenharmony_ci#define QLCNIC_LB_PKT_POLL_COUNT 20 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[]) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00}; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci memcpy(data, mac, ETH_ALEN); 10298c2ecf20Sopenharmony_ci memcpy(data + ETH_ALEN, mac, ETH_ALEN); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data)); 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciint qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci unsigned char buff[QLCNIC_ILB_PKT_SIZE]; 10378c2ecf20Sopenharmony_ci qlcnic_create_loopback_buff(buff, mac); 10388c2ecf20Sopenharmony_ci return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ciint qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; 10448c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0]; 10458c2ecf20Sopenharmony_ci struct sk_buff *skb; 10468c2ecf20Sopenharmony_ci int i, loop, cnt = 0; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) { 10498c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE); 10508c2ecf20Sopenharmony_ci if (!skb) 10518c2ecf20Sopenharmony_ci goto error; 10528c2ecf20Sopenharmony_ci qlcnic_create_loopback_buff(skb->data, adapter->mac_addr); 10538c2ecf20Sopenharmony_ci skb_put(skb, QLCNIC_ILB_PKT_SIZE); 10548c2ecf20Sopenharmony_ci adapter->ahw->diag_cnt = 0; 10558c2ecf20Sopenharmony_ci qlcnic_xmit_frame(skb, adapter->netdev); 10568c2ecf20Sopenharmony_ci loop = 0; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci do { 10598c2ecf20Sopenharmony_ci msleep(QLCNIC_LB_PKT_POLL_DELAY_MSEC); 10608c2ecf20Sopenharmony_ci qlcnic_process_rcv_ring_diag(sds_ring); 10618c2ecf20Sopenharmony_ci if (loop++ > QLCNIC_LB_PKT_POLL_COUNT) 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci } while (!adapter->ahw->diag_cnt); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (!adapter->ahw->diag_cnt) 10688c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, 10698c2ecf20Sopenharmony_ci "LB Test: packet #%d was not received\n", 10708c2ecf20Sopenharmony_ci i + 1); 10718c2ecf20Sopenharmony_ci else 10728c2ecf20Sopenharmony_ci cnt++; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci if (cnt != i) { 10758c2ecf20Sopenharmony_cierror: 10768c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 10778c2ecf20Sopenharmony_ci "LB Test: failed, TX[%d], RX[%d]\n", i, cnt); 10788c2ecf20Sopenharmony_ci if (mode != QLCNIC_ILB_MODE) 10798c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, 10808c2ecf20Sopenharmony_ci "WARNING: Please check loopback cable\n"); 10818c2ecf20Sopenharmony_ci return -1; 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci return 0; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic int qlcnic_loopback_test(struct net_device *netdev, u8 mode) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 10898c2ecf20Sopenharmony_ci int drv_tx_rings = adapter->drv_tx_rings; 10908c2ecf20Sopenharmony_ci int drv_sds_rings = adapter->drv_sds_rings; 10918c2ecf20Sopenharmony_ci struct qlcnic_host_sds_ring *sds_ring; 10928c2ecf20Sopenharmony_ci struct qlcnic_hardware_context *ahw = adapter->ahw; 10938c2ecf20Sopenharmony_ci int loop = 0; 10948c2ecf20Sopenharmony_ci int ret; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 10978c2ecf20Sopenharmony_ci return qlcnic_83xx_loopback_test(netdev, mode); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) { 11008c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, 11018c2ecf20Sopenharmony_ci "Firmware do not support loopback test\n"); 11028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, "%s loopback test in progress\n", 11068c2ecf20Sopenharmony_ci mode == QLCNIC_ILB_MODE ? "internal" : "external"); 11078c2ecf20Sopenharmony_ci if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { 11088c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, 11098c2ecf20Sopenharmony_ci "Loopback test not supported in nonprivileged mode\n"); 11108c2ecf20Sopenharmony_ci return 0; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 11148c2ecf20Sopenharmony_ci return -EBUSY; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST); 11178c2ecf20Sopenharmony_ci if (ret) 11188c2ecf20Sopenharmony_ci goto clear_it; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci sds_ring = &adapter->recv_ctx->sds_rings[0]; 11218c2ecf20Sopenharmony_ci ret = qlcnic_set_lb_mode(adapter, mode); 11228c2ecf20Sopenharmony_ci if (ret) 11238c2ecf20Sopenharmony_ci goto free_res; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci ahw->diag_cnt = 0; 11268c2ecf20Sopenharmony_ci do { 11278c2ecf20Sopenharmony_ci msleep(500); 11288c2ecf20Sopenharmony_ci qlcnic_process_rcv_ring_diag(sds_ring); 11298c2ecf20Sopenharmony_ci if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) { 11308c2ecf20Sopenharmony_ci netdev_info(netdev, 11318c2ecf20Sopenharmony_ci "Firmware didn't sent link up event to loopback request\n"); 11328c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 11338c2ecf20Sopenharmony_ci goto free_res; 11348c2ecf20Sopenharmony_ci } else if (adapter->ahw->diag_cnt) { 11358c2ecf20Sopenharmony_ci ret = adapter->ahw->diag_cnt; 11368c2ecf20Sopenharmony_ci goto free_res; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state)); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci ret = qlcnic_do_lb_test(adapter, mode); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci qlcnic_clear_lb_mode(adapter, mode); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci free_res: 11458c2ecf20Sopenharmony_ci qlcnic_diag_free_res(netdev, drv_sds_rings); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci clear_it: 11488c2ecf20Sopenharmony_ci adapter->drv_sds_rings = drv_sds_rings; 11498c2ecf20Sopenharmony_ci adapter->drv_tx_rings = drv_tx_rings; 11508c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_RESETTING, &adapter->state); 11518c2ecf20Sopenharmony_ci return ret; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cistatic void 11558c2ecf20Sopenharmony_ciqlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, 11568c2ecf20Sopenharmony_ci u64 *data) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci data[0] = qlcnic_reg_test(dev); 11618c2ecf20Sopenharmony_ci if (data[0]) 11628c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci data[1] = (u64) qlcnic_test_link(dev); 11658c2ecf20Sopenharmony_ci if (data[1]) 11668c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (eth_test->flags & ETH_TEST_FL_OFFLINE) { 11698c2ecf20Sopenharmony_ci data[2] = qlcnic_irq_test(dev); 11708c2ecf20Sopenharmony_ci if (data[2]) 11718c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE); 11748c2ecf20Sopenharmony_ci if (data[3]) 11758c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) { 11788c2ecf20Sopenharmony_ci data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE); 11798c2ecf20Sopenharmony_ci if (data[4]) 11808c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 11818c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci data[5] = qlcnic_eeprom_test(dev); 11858c2ecf20Sopenharmony_ci if (data[5]) 11868c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic void 11918c2ecf20Sopenharmony_ciqlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 11948c2ecf20Sopenharmony_ci int index, i, num_stats; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci switch (stringset) { 11978c2ecf20Sopenharmony_ci case ETH_SS_TEST: 11988c2ecf20Sopenharmony_ci memcpy(data, *qlcnic_gstrings_test, 11998c2ecf20Sopenharmony_ci QLCNIC_TEST_LEN * ETH_GSTRING_LEN); 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci case ETH_SS_STATS: 12028c2ecf20Sopenharmony_ci num_stats = ARRAY_SIZE(qlcnic_tx_queue_stats_strings); 12038c2ecf20Sopenharmony_ci for (i = 0; i < adapter->drv_tx_rings; i++) { 12048c2ecf20Sopenharmony_ci for (index = 0; index < num_stats; index++) { 12058c2ecf20Sopenharmony_ci sprintf(data, "tx_queue_%d %s", i, 12068c2ecf20Sopenharmony_ci qlcnic_tx_queue_stats_strings[index]); 12078c2ecf20Sopenharmony_ci data += ETH_GSTRING_LEN; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci for (index = 0; index < QLCNIC_STATS_LEN; index++) { 12128c2ecf20Sopenharmony_ci memcpy(data + index * ETH_GSTRING_LEN, 12138c2ecf20Sopenharmony_ci qlcnic_gstrings_stats[index].stat_string, 12148c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 12188c2ecf20Sopenharmony_ci num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings); 12198c2ecf20Sopenharmony_ci for (i = 0; i < num_stats; i++, index++) 12208c2ecf20Sopenharmony_ci memcpy(data + index * ETH_GSTRING_LEN, 12218c2ecf20Sopenharmony_ci qlcnic_83xx_tx_stats_strings[i], 12228c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 12238c2ecf20Sopenharmony_ci num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings); 12248c2ecf20Sopenharmony_ci for (i = 0; i < num_stats; i++, index++) 12258c2ecf20Sopenharmony_ci memcpy(data + index * ETH_GSTRING_LEN, 12268c2ecf20Sopenharmony_ci qlcnic_83xx_mac_stats_strings[i], 12278c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 12288c2ecf20Sopenharmony_ci num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings); 12298c2ecf20Sopenharmony_ci for (i = 0; i < num_stats; i++, index++) 12308c2ecf20Sopenharmony_ci memcpy(data + index * ETH_GSTRING_LEN, 12318c2ecf20Sopenharmony_ci qlcnic_83xx_rx_stats_strings[i], 12328c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 12338c2ecf20Sopenharmony_ci return; 12348c2ecf20Sopenharmony_ci } else { 12358c2ecf20Sopenharmony_ci num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings); 12368c2ecf20Sopenharmony_ci for (i = 0; i < num_stats; i++, index++) 12378c2ecf20Sopenharmony_ci memcpy(data + index * ETH_GSTRING_LEN, 12388c2ecf20Sopenharmony_ci qlcnic_83xx_mac_stats_strings[i], 12398c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) 12428c2ecf20Sopenharmony_ci return; 12438c2ecf20Sopenharmony_ci num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats); 12448c2ecf20Sopenharmony_ci for (i = 0; i < num_stats; index++, i++) { 12458c2ecf20Sopenharmony_ci memcpy(data + index * ETH_GSTRING_LEN, 12468c2ecf20Sopenharmony_ci qlcnic_device_gstrings_stats[i], 12478c2ecf20Sopenharmony_ci ETH_GSTRING_LEN); 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic u64 *qlcnic_fill_stats(u64 *data, void *stats, int type) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci if (type == QLCNIC_MAC_STATS) { 12558c2ecf20Sopenharmony_ci struct qlcnic_mac_statistics *mac_stats = 12568c2ecf20Sopenharmony_ci (struct qlcnic_mac_statistics *)stats; 12578c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames); 12588c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes); 12598c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts); 12608c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts); 12618c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt); 12628c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt); 12638c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts); 12648c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts); 12658c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts); 12668c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts); 12678c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts); 12688c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts); 12698c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts); 12708c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames); 12718c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes); 12728c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts); 12738c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts); 12748c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt); 12758c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt); 12768c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts); 12778c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts); 12788c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts); 12798c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts); 12808c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts); 12818c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts); 12828c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts); 12838c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error); 12848c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small); 12858c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large); 12868c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber); 12878c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped); 12888c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error); 12898c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error); 12908c2ecf20Sopenharmony_ci } else if (type == QLCNIC_ESW_STATS) { 12918c2ecf20Sopenharmony_ci struct __qlcnic_esw_statistics *esw_stats = 12928c2ecf20Sopenharmony_ci (struct __qlcnic_esw_statistics *)stats; 12938c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames); 12948c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames); 12958c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames); 12968c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames); 12978c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->errors); 12988c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames); 12998c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci return data; 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_civoid qlcnic_update_stats(struct qlcnic_adapter *adapter) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci struct qlcnic_tx_queue_stats tx_stats; 13078c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 13088c2ecf20Sopenharmony_ci int ring; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci memset(&tx_stats, 0, sizeof(tx_stats)); 13118c2ecf20Sopenharmony_ci for (ring = 0; ring < adapter->drv_tx_rings; ring++) { 13128c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 13138c2ecf20Sopenharmony_ci tx_stats.xmit_on += tx_ring->tx_stats.xmit_on; 13148c2ecf20Sopenharmony_ci tx_stats.xmit_off += tx_ring->tx_stats.xmit_off; 13158c2ecf20Sopenharmony_ci tx_stats.xmit_called += tx_ring->tx_stats.xmit_called; 13168c2ecf20Sopenharmony_ci tx_stats.xmit_finished += tx_ring->tx_stats.xmit_finished; 13178c2ecf20Sopenharmony_ci tx_stats.tx_bytes += tx_ring->tx_stats.tx_bytes; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci adapter->stats.xmit_on = tx_stats.xmit_on; 13218c2ecf20Sopenharmony_ci adapter->stats.xmit_off = tx_stats.xmit_off; 13228c2ecf20Sopenharmony_ci adapter->stats.xmitcalled = tx_stats.xmit_called; 13238c2ecf20Sopenharmony_ci adapter->stats.xmitfinished = tx_stats.xmit_finished; 13248c2ecf20Sopenharmony_ci adapter->stats.txbytes = tx_stats.tx_bytes; 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic u64 *qlcnic_fill_tx_queue_stats(u64 *data, void *stats) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci tx_ring = (struct qlcnic_host_tx_ring *)stats; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_on); 13348c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_off); 13358c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_called); 13368c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_finished); 13378c2ecf20Sopenharmony_ci *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.tx_bytes); 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci return data; 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic void qlcnic_get_ethtool_stats(struct net_device *dev, 13438c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 13468c2ecf20Sopenharmony_ci struct qlcnic_host_tx_ring *tx_ring; 13478c2ecf20Sopenharmony_ci struct qlcnic_esw_statistics port_stats; 13488c2ecf20Sopenharmony_ci struct qlcnic_mac_statistics mac_stats; 13498c2ecf20Sopenharmony_ci int index, ret, length, size, ring; 13508c2ecf20Sopenharmony_ci char *p; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci memset(data, 0, stats->n_stats * sizeof(u64)); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci for (ring = 0, index = 0; ring < adapter->drv_tx_rings; ring++) { 13558c2ecf20Sopenharmony_ci if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC) { 13568c2ecf20Sopenharmony_ci tx_ring = &adapter->tx_ring[ring]; 13578c2ecf20Sopenharmony_ci data = qlcnic_fill_tx_queue_stats(data, tx_ring); 13588c2ecf20Sopenharmony_ci qlcnic_update_stats(adapter); 13598c2ecf20Sopenharmony_ci } else { 13608c2ecf20Sopenharmony_ci data += QLCNIC_TX_STATS_LEN; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci length = QLCNIC_STATS_LEN; 13658c2ecf20Sopenharmony_ci for (index = 0; index < length; index++) { 13668c2ecf20Sopenharmony_ci p = (char *)adapter + qlcnic_gstrings_stats[index].stat_offset; 13678c2ecf20Sopenharmony_ci size = qlcnic_gstrings_stats[index].sizeof_stat; 13688c2ecf20Sopenharmony_ci *data++ = (size == sizeof(u64)) ? (*(u64 *)p) : ((*(u32 *)p)); 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) { 13728c2ecf20Sopenharmony_ci if (adapter->ahw->linkup) 13738c2ecf20Sopenharmony_ci qlcnic_83xx_get_stats(adapter, data); 13748c2ecf20Sopenharmony_ci return; 13758c2ecf20Sopenharmony_ci } else { 13768c2ecf20Sopenharmony_ci /* Retrieve MAC statistics from firmware */ 13778c2ecf20Sopenharmony_ci memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics)); 13788c2ecf20Sopenharmony_ci qlcnic_get_mac_stats(adapter, &mac_stats); 13798c2ecf20Sopenharmony_ci data = qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) 13838c2ecf20Sopenharmony_ci return; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics)); 13868c2ecf20Sopenharmony_ci ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, 13878c2ecf20Sopenharmony_ci QLCNIC_QUERY_RX_COUNTER, &port_stats.rx); 13888c2ecf20Sopenharmony_ci if (ret) 13898c2ecf20Sopenharmony_ci return; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci data = qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS); 13928c2ecf20Sopenharmony_ci ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func, 13938c2ecf20Sopenharmony_ci QLCNIC_QUERY_TX_COUNTER, &port_stats.tx); 13948c2ecf20Sopenharmony_ci if (ret) 13958c2ecf20Sopenharmony_ci return; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS); 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic int qlcnic_set_led(struct net_device *dev, 14018c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 14048c2ecf20Sopenharmony_ci int drv_sds_rings = adapter->drv_sds_rings; 14058c2ecf20Sopenharmony_ci int err = -EIO, active = 1; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 14088c2ecf20Sopenharmony_ci return qlcnic_83xx_set_led(dev, state); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) { 14118c2ecf20Sopenharmony_ci netdev_warn(dev, "LED test not supported for non " 14128c2ecf20Sopenharmony_ci "privilege function\n"); 14138c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci switch (state) { 14178c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 14188c2ecf20Sopenharmony_ci if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) 14198c2ecf20Sopenharmony_ci return -EBUSY; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_RESETTING, &adapter->state)) 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { 14258c2ecf20Sopenharmony_ci if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state); 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) { 14318c2ecf20Sopenharmony_ci err = 0; 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 14368c2ecf20Sopenharmony_ci "Failed to set LED blink state.\n"); 14378c2ecf20Sopenharmony_ci break; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 14408c2ecf20Sopenharmony_ci active = 0; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_RESETTING, &adapter->state)) 14438c2ecf20Sopenharmony_ci break; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) { 14468c2ecf20Sopenharmony_ci if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state); 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (adapter->nic_ops->config_led(adapter, 0, 0xf)) 14528c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 14538c2ecf20Sopenharmony_ci "Failed to reset LED blink state.\n"); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci break; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci default: 14588c2ecf20Sopenharmony_ci return -EINVAL; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) 14628c2ecf20Sopenharmony_ci qlcnic_diag_free_res(dev, drv_sds_rings); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (!active || err) 14658c2ecf20Sopenharmony_ci clear_bit(__QLCNIC_LED_ENABLE, &adapter->state); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci return err; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic void 14718c2ecf20Sopenharmony_ciqlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 14748c2ecf20Sopenharmony_ci u32 wol_cfg; 14758c2ecf20Sopenharmony_ci int err = 0; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 14788c2ecf20Sopenharmony_ci return; 14798c2ecf20Sopenharmony_ci wol->supported = 0; 14808c2ecf20Sopenharmony_ci wol->wolopts = 0; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); 14838c2ecf20Sopenharmony_ci if (err == -EIO) 14848c2ecf20Sopenharmony_ci return; 14858c2ecf20Sopenharmony_ci if (wol_cfg & (1UL << adapter->portnum)) 14868c2ecf20Sopenharmony_ci wol->supported |= WAKE_MAGIC; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); 14898c2ecf20Sopenharmony_ci if (wol_cfg & (1UL << adapter->portnum)) 14908c2ecf20Sopenharmony_ci wol->wolopts |= WAKE_MAGIC; 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic int 14948c2ecf20Sopenharmony_ciqlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(dev); 14978c2ecf20Sopenharmony_ci u32 wol_cfg; 14988c2ecf20Sopenharmony_ci int err = 0; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci if (qlcnic_83xx_check(adapter)) 15018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15028c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) 15038c2ecf20Sopenharmony_ci return -EINVAL; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); 15068c2ecf20Sopenharmony_ci if (err == -EIO) 15078c2ecf20Sopenharmony_ci return err; 15088c2ecf20Sopenharmony_ci if (!(wol_cfg & (1 << adapter->portnum))) 15098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); 15128c2ecf20Sopenharmony_ci if (err == -EIO) 15138c2ecf20Sopenharmony_ci return err; 15148c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) 15158c2ecf20Sopenharmony_ci wol_cfg |= 1UL << adapter->portnum; 15168c2ecf20Sopenharmony_ci else 15178c2ecf20Sopenharmony_ci wol_cfg &= ~(1UL << adapter->portnum); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci QLCWR32(adapter, QLCNIC_WOL_CONFIG, wol_cfg); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return 0; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci/* 15258c2ecf20Sopenharmony_ci * Set the coalescing parameters. Currently only normal is supported. 15268c2ecf20Sopenharmony_ci * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the 15278c2ecf20Sopenharmony_ci * firmware coalescing to default. 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_cistatic int qlcnic_set_intr_coalesce(struct net_device *netdev, 15308c2ecf20Sopenharmony_ci struct ethtool_coalesce *ethcoal) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 15338c2ecf20Sopenharmony_ci int err; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) 15368c2ecf20Sopenharmony_ci return -EINVAL; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* 15398c2ecf20Sopenharmony_ci * Return Error if unsupported values or 15408c2ecf20Sopenharmony_ci * unsupported parameters are set. 15418c2ecf20Sopenharmony_ci */ 15428c2ecf20Sopenharmony_ci if (ethcoal->rx_coalesce_usecs > 0xffff || 15438c2ecf20Sopenharmony_ci ethcoal->rx_max_coalesced_frames > 0xffff || 15448c2ecf20Sopenharmony_ci ethcoal->tx_coalesce_usecs > 0xffff || 15458c2ecf20Sopenharmony_ci ethcoal->tx_max_coalesced_frames > 0xffff) 15468c2ecf20Sopenharmony_ci return -EINVAL; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci err = qlcnic_config_intr_coalesce(adapter, ethcoal); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci return err; 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic int qlcnic_get_intr_coalesce(struct net_device *netdev, 15548c2ecf20Sopenharmony_ci struct ethtool_coalesce *ethcoal) 15558c2ecf20Sopenharmony_ci{ 15568c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) 15598c2ecf20Sopenharmony_ci return -EINVAL; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us; 15628c2ecf20Sopenharmony_ci ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets; 15638c2ecf20Sopenharmony_ci ethcoal->tx_coalesce_usecs = adapter->ahw->coal.tx_time_us; 15648c2ecf20Sopenharmony_ci ethcoal->tx_max_coalesced_frames = adapter->ahw->coal.tx_packets; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci return 0; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic u32 qlcnic_get_msglevel(struct net_device *netdev) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci return adapter->ahw->msg_enable; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci adapter->ahw->msg_enable = msglvl; 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ciint qlcnic_enable_fw_dump_state(struct qlcnic_adapter *adapter) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 15868c2ecf20Sopenharmony_ci u32 val; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (qlcnic_84xx_check(adapter)) { 15898c2ecf20Sopenharmony_ci if (qlcnic_83xx_lock_driver(adapter)) 15908c2ecf20Sopenharmony_ci return -EBUSY; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); 15938c2ecf20Sopenharmony_ci val &= ~QLC_83XX_IDC_DISABLE_FW_DUMP; 15948c2ecf20Sopenharmony_ci QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci qlcnic_83xx_unlock_driver(adapter); 15978c2ecf20Sopenharmony_ci } else { 15988c2ecf20Sopenharmony_ci fw_dump->enable = true; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "FW dump enabled\n"); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci return 0; 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_cistatic int qlcnic_disable_fw_dump_state(struct qlcnic_adapter *adapter) 16078c2ecf20Sopenharmony_ci{ 16088c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 16098c2ecf20Sopenharmony_ci u32 val; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (qlcnic_84xx_check(adapter)) { 16128c2ecf20Sopenharmony_ci if (qlcnic_83xx_lock_driver(adapter)) 16138c2ecf20Sopenharmony_ci return -EBUSY; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); 16168c2ecf20Sopenharmony_ci val |= QLC_83XX_IDC_DISABLE_FW_DUMP; 16178c2ecf20Sopenharmony_ci QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci qlcnic_83xx_unlock_driver(adapter); 16208c2ecf20Sopenharmony_ci } else { 16218c2ecf20Sopenharmony_ci fw_dump->enable = false; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "FW dump disabled\n"); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci return 0; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cibool qlcnic_check_fw_dump_state(struct qlcnic_adapter *adapter) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 16328c2ecf20Sopenharmony_ci bool state; 16338c2ecf20Sopenharmony_ci u32 val; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (qlcnic_84xx_check(adapter)) { 16368c2ecf20Sopenharmony_ci val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); 16378c2ecf20Sopenharmony_ci state = (val & QLC_83XX_IDC_DISABLE_FW_DUMP) ? false : true; 16388c2ecf20Sopenharmony_ci } else { 16398c2ecf20Sopenharmony_ci state = fw_dump->enable; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci return state; 16438c2ecf20Sopenharmony_ci} 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_cistatic int 16468c2ecf20Sopenharmony_ciqlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) 16478c2ecf20Sopenharmony_ci{ 16488c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 16498c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci if (!fw_dump->tmpl_hdr) { 16528c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, "FW Dump not supported\n"); 16538c2ecf20Sopenharmony_ci return -ENOTSUPP; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (fw_dump->clr) 16578c2ecf20Sopenharmony_ci dump->len = fw_dump->tmpl_hdr_size + fw_dump->size; 16588c2ecf20Sopenharmony_ci else 16598c2ecf20Sopenharmony_ci dump->len = 0; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (!qlcnic_check_fw_dump_state(adapter)) 16628c2ecf20Sopenharmony_ci dump->flag = ETH_FW_DUMP_DISABLE; 16638c2ecf20Sopenharmony_ci else 16648c2ecf20Sopenharmony_ci dump->flag = fw_dump->cap_mask; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci dump->version = adapter->fw_version; 16678c2ecf20Sopenharmony_ci return 0; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_cistatic int 16718c2ecf20Sopenharmony_ciqlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, 16728c2ecf20Sopenharmony_ci void *buffer) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci int i, copy_sz; 16758c2ecf20Sopenharmony_ci u32 *hdr_ptr; 16768c2ecf20Sopenharmony_ci __le32 *data; 16778c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 16788c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (!fw_dump->tmpl_hdr) { 16818c2ecf20Sopenharmony_ci netdev_err(netdev, "FW Dump not supported\n"); 16828c2ecf20Sopenharmony_ci return -ENOTSUPP; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci if (!fw_dump->clr) { 16868c2ecf20Sopenharmony_ci netdev_info(netdev, "Dump not available\n"); 16878c2ecf20Sopenharmony_ci return -EINVAL; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci /* Copy template header first */ 16918c2ecf20Sopenharmony_ci copy_sz = fw_dump->tmpl_hdr_size; 16928c2ecf20Sopenharmony_ci hdr_ptr = (u32 *)fw_dump->tmpl_hdr; 16938c2ecf20Sopenharmony_ci data = buffer; 16948c2ecf20Sopenharmony_ci for (i = 0; i < copy_sz/sizeof(u32); i++) 16958c2ecf20Sopenharmony_ci *data++ = cpu_to_le32(*hdr_ptr++); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* Copy captured dump data */ 16988c2ecf20Sopenharmony_ci memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size); 16998c2ecf20Sopenharmony_ci dump->len = copy_sz + fw_dump->size; 17008c2ecf20Sopenharmony_ci dump->flag = fw_dump->cap_mask; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* Free dump area once data has been captured */ 17038c2ecf20Sopenharmony_ci vfree(fw_dump->data); 17048c2ecf20Sopenharmony_ci fw_dump->data = NULL; 17058c2ecf20Sopenharmony_ci fw_dump->clr = 0; 17068c2ecf20Sopenharmony_ci netdev_info(netdev, "extracted the FW dump Successfully\n"); 17078c2ecf20Sopenharmony_ci return 0; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_cistatic int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask) 17118c2ecf20Sopenharmony_ci{ 17128c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 17138c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (!qlcnic_check_fw_dump_state(adapter)) { 17168c2ecf20Sopenharmony_ci netdev_info(netdev, 17178c2ecf20Sopenharmony_ci "Can not change driver mask to 0x%x. FW dump not enabled\n", 17188c2ecf20Sopenharmony_ci mask); 17198c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci fw_dump->cap_mask = mask; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci /* Store new capture mask in template header as well*/ 17258c2ecf20Sopenharmony_ci qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask); 17288c2ecf20Sopenharmony_ci return 0; 17298c2ecf20Sopenharmony_ci} 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_cistatic int 17328c2ecf20Sopenharmony_ciqlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci struct qlcnic_adapter *adapter = netdev_priv(netdev); 17358c2ecf20Sopenharmony_ci struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 17368c2ecf20Sopenharmony_ci bool valid_mask = false; 17378c2ecf20Sopenharmony_ci int i, ret = 0; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci switch (val->flag) { 17408c2ecf20Sopenharmony_ci case QLCNIC_FORCE_FW_DUMP_KEY: 17418c2ecf20Sopenharmony_ci if (!fw_dump->tmpl_hdr) { 17428c2ecf20Sopenharmony_ci netdev_err(netdev, "FW dump not supported\n"); 17438c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 17448c2ecf20Sopenharmony_ci break; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (!qlcnic_check_fw_dump_state(adapter)) { 17488c2ecf20Sopenharmony_ci netdev_info(netdev, "FW dump not enabled\n"); 17498c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci if (fw_dump->clr) { 17548c2ecf20Sopenharmony_ci netdev_info(netdev, 17558c2ecf20Sopenharmony_ci "Previous dump not cleared, not forcing dump\n"); 17568c2ecf20Sopenharmony_ci break; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci netdev_info(netdev, "Forcing a FW dump\n"); 17608c2ecf20Sopenharmony_ci qlcnic_dev_request_reset(adapter, val->flag); 17618c2ecf20Sopenharmony_ci break; 17628c2ecf20Sopenharmony_ci case QLCNIC_DISABLE_FW_DUMP: 17638c2ecf20Sopenharmony_ci if (!fw_dump->tmpl_hdr) { 17648c2ecf20Sopenharmony_ci netdev_err(netdev, "FW dump not supported\n"); 17658c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 17668c2ecf20Sopenharmony_ci break; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci ret = qlcnic_disable_fw_dump_state(adapter); 17708c2ecf20Sopenharmony_ci break; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci case QLCNIC_ENABLE_FW_DUMP: 17738c2ecf20Sopenharmony_ci if (!fw_dump->tmpl_hdr) { 17748c2ecf20Sopenharmony_ci netdev_err(netdev, "FW dump not supported\n"); 17758c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 17768c2ecf20Sopenharmony_ci break; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci ret = qlcnic_enable_fw_dump_state(adapter); 17808c2ecf20Sopenharmony_ci break; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci case QLCNIC_FORCE_FW_RESET: 17838c2ecf20Sopenharmony_ci netdev_info(netdev, "Forcing a FW reset\n"); 17848c2ecf20Sopenharmony_ci qlcnic_dev_request_reset(adapter, val->flag); 17858c2ecf20Sopenharmony_ci adapter->flags &= ~QLCNIC_FW_RESET_OWNER; 17868c2ecf20Sopenharmony_ci break; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci case QLCNIC_SET_QUIESCENT: 17898c2ecf20Sopenharmony_ci case QLCNIC_RESET_QUIESCENT: 17908c2ecf20Sopenharmony_ci if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) 17918c2ecf20Sopenharmony_ci netdev_info(netdev, "Device is in non-operational state\n"); 17928c2ecf20Sopenharmony_ci break; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci default: 17958c2ecf20Sopenharmony_ci if (!fw_dump->tmpl_hdr) { 17968c2ecf20Sopenharmony_ci netdev_err(netdev, "FW dump not supported\n"); 17978c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 17988c2ecf20Sopenharmony_ci break; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) { 18028c2ecf20Sopenharmony_ci if (val->flag == qlcnic_fw_dump_level[i]) { 18038c2ecf20Sopenharmony_ci valid_mask = true; 18048c2ecf20Sopenharmony_ci break; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (valid_mask) { 18098c2ecf20Sopenharmony_ci ret = qlcnic_set_dump_mask(adapter, val->flag); 18108c2ecf20Sopenharmony_ci } else { 18118c2ecf20Sopenharmony_ci netdev_info(netdev, "Invalid dump level: 0x%x\n", 18128c2ecf20Sopenharmony_ci val->flag); 18138c2ecf20Sopenharmony_ci ret = -EINVAL; 18148c2ecf20Sopenharmony_ci } 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci return ret; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ciconst struct ethtool_ops qlcnic_ethtool_ops = { 18208c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 18218c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES, 18228c2ecf20Sopenharmony_ci .get_drvinfo = qlcnic_get_drvinfo, 18238c2ecf20Sopenharmony_ci .get_regs_len = qlcnic_get_regs_len, 18248c2ecf20Sopenharmony_ci .get_regs = qlcnic_get_regs, 18258c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 18268c2ecf20Sopenharmony_ci .get_eeprom_len = qlcnic_get_eeprom_len, 18278c2ecf20Sopenharmony_ci .get_eeprom = qlcnic_get_eeprom, 18288c2ecf20Sopenharmony_ci .get_ringparam = qlcnic_get_ringparam, 18298c2ecf20Sopenharmony_ci .set_ringparam = qlcnic_set_ringparam, 18308c2ecf20Sopenharmony_ci .get_channels = qlcnic_get_channels, 18318c2ecf20Sopenharmony_ci .set_channels = qlcnic_set_channels, 18328c2ecf20Sopenharmony_ci .get_pauseparam = qlcnic_get_pauseparam, 18338c2ecf20Sopenharmony_ci .set_pauseparam = qlcnic_set_pauseparam, 18348c2ecf20Sopenharmony_ci .get_wol = qlcnic_get_wol, 18358c2ecf20Sopenharmony_ci .set_wol = qlcnic_set_wol, 18368c2ecf20Sopenharmony_ci .self_test = qlcnic_diag_test, 18378c2ecf20Sopenharmony_ci .get_strings = qlcnic_get_strings, 18388c2ecf20Sopenharmony_ci .get_ethtool_stats = qlcnic_get_ethtool_stats, 18398c2ecf20Sopenharmony_ci .get_sset_count = qlcnic_get_sset_count, 18408c2ecf20Sopenharmony_ci .get_coalesce = qlcnic_get_intr_coalesce, 18418c2ecf20Sopenharmony_ci .set_coalesce = qlcnic_set_intr_coalesce, 18428c2ecf20Sopenharmony_ci .set_phys_id = qlcnic_set_led, 18438c2ecf20Sopenharmony_ci .set_msglevel = qlcnic_set_msglevel, 18448c2ecf20Sopenharmony_ci .get_msglevel = qlcnic_get_msglevel, 18458c2ecf20Sopenharmony_ci .get_dump_flag = qlcnic_get_dump_flag, 18468c2ecf20Sopenharmony_ci .get_dump_data = qlcnic_get_dump_data, 18478c2ecf20Sopenharmony_ci .set_dump = qlcnic_set_dump, 18488c2ecf20Sopenharmony_ci .get_link_ksettings = qlcnic_get_link_ksettings, 18498c2ecf20Sopenharmony_ci .set_link_ksettings = qlcnic_set_link_ksettings, 18508c2ecf20Sopenharmony_ci}; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ciconst struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = { 18538c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 18548c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES, 18558c2ecf20Sopenharmony_ci .get_drvinfo = qlcnic_get_drvinfo, 18568c2ecf20Sopenharmony_ci .get_regs_len = qlcnic_get_regs_len, 18578c2ecf20Sopenharmony_ci .get_regs = qlcnic_get_regs, 18588c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 18598c2ecf20Sopenharmony_ci .get_eeprom_len = qlcnic_get_eeprom_len, 18608c2ecf20Sopenharmony_ci .get_eeprom = qlcnic_get_eeprom, 18618c2ecf20Sopenharmony_ci .get_ringparam = qlcnic_get_ringparam, 18628c2ecf20Sopenharmony_ci .set_ringparam = qlcnic_set_ringparam, 18638c2ecf20Sopenharmony_ci .get_channels = qlcnic_get_channels, 18648c2ecf20Sopenharmony_ci .get_pauseparam = qlcnic_get_pauseparam, 18658c2ecf20Sopenharmony_ci .get_wol = qlcnic_get_wol, 18668c2ecf20Sopenharmony_ci .get_strings = qlcnic_get_strings, 18678c2ecf20Sopenharmony_ci .get_ethtool_stats = qlcnic_get_ethtool_stats, 18688c2ecf20Sopenharmony_ci .get_sset_count = qlcnic_get_sset_count, 18698c2ecf20Sopenharmony_ci .get_coalesce = qlcnic_get_intr_coalesce, 18708c2ecf20Sopenharmony_ci .set_coalesce = qlcnic_set_intr_coalesce, 18718c2ecf20Sopenharmony_ci .set_msglevel = qlcnic_set_msglevel, 18728c2ecf20Sopenharmony_ci .get_msglevel = qlcnic_get_msglevel, 18738c2ecf20Sopenharmony_ci .get_link_ksettings = qlcnic_get_link_ksettings, 18748c2ecf20Sopenharmony_ci}; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ciconst struct ethtool_ops qlcnic_ethtool_failed_ops = { 18778c2ecf20Sopenharmony_ci .get_drvinfo = qlcnic_get_drvinfo, 18788c2ecf20Sopenharmony_ci .set_msglevel = qlcnic_set_msglevel, 18798c2ecf20Sopenharmony_ci .get_msglevel = qlcnic_get_msglevel, 18808c2ecf20Sopenharmony_ci .set_dump = qlcnic_set_dump, 18818c2ecf20Sopenharmony_ci .get_link_ksettings = qlcnic_get_link_ksettings, 18828c2ecf20Sopenharmony_ci}; 1883