18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Chelsio Communications. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/firmware.h> 78c2ecf20Sopenharmony_ci#include <linux/mdio.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "cxgb4.h" 108c2ecf20Sopenharmony_ci#include "t4_regs.h" 118c2ecf20Sopenharmony_ci#include "t4fw_api.h" 128c2ecf20Sopenharmony_ci#include "cxgb4_cudbg.h" 138c2ecf20Sopenharmony_ci#include "cxgb4_filter.h" 148c2ecf20Sopenharmony_ci#include "cxgb4_tc_flower.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define EEPROM_MAGIC 0x38E2F10C 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic u32 get_msglevel(struct net_device *dev) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci return netdev2adap(dev)->msg_enable; 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void set_msglevel(struct net_device *dev, u32 val) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci netdev2adap(dev)->msg_enable = val; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cienum cxgb4_ethtool_tests { 298c2ecf20Sopenharmony_ci CXGB4_ETHTOOL_LB_TEST, 308c2ecf20Sopenharmony_ci CXGB4_ETHTOOL_MAX_TEST, 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic const char cxgb4_selftest_strings[CXGB4_ETHTOOL_MAX_TEST][ETH_GSTRING_LEN] = { 348c2ecf20Sopenharmony_ci "Loop back test (offline)", 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const char * const flash_region_strings[] = { 388c2ecf20Sopenharmony_ci "All", 398c2ecf20Sopenharmony_ci "Firmware", 408c2ecf20Sopenharmony_ci "PHY Firmware", 418c2ecf20Sopenharmony_ci "Boot", 428c2ecf20Sopenharmony_ci "Boot CFG", 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic const char stats_strings[][ETH_GSTRING_LEN] = { 468c2ecf20Sopenharmony_ci "tx_octets_ok ", 478c2ecf20Sopenharmony_ci "tx_frames_ok ", 488c2ecf20Sopenharmony_ci "tx_broadcast_frames ", 498c2ecf20Sopenharmony_ci "tx_multicast_frames ", 508c2ecf20Sopenharmony_ci "tx_unicast_frames ", 518c2ecf20Sopenharmony_ci "tx_error_frames ", 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci "tx_frames_64 ", 548c2ecf20Sopenharmony_ci "tx_frames_65_to_127 ", 558c2ecf20Sopenharmony_ci "tx_frames_128_to_255 ", 568c2ecf20Sopenharmony_ci "tx_frames_256_to_511 ", 578c2ecf20Sopenharmony_ci "tx_frames_512_to_1023 ", 588c2ecf20Sopenharmony_ci "tx_frames_1024_to_1518 ", 598c2ecf20Sopenharmony_ci "tx_frames_1519_to_max ", 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci "tx_frames_dropped ", 628c2ecf20Sopenharmony_ci "tx_pause_frames ", 638c2ecf20Sopenharmony_ci "tx_ppp0_frames ", 648c2ecf20Sopenharmony_ci "tx_ppp1_frames ", 658c2ecf20Sopenharmony_ci "tx_ppp2_frames ", 668c2ecf20Sopenharmony_ci "tx_ppp3_frames ", 678c2ecf20Sopenharmony_ci "tx_ppp4_frames ", 688c2ecf20Sopenharmony_ci "tx_ppp5_frames ", 698c2ecf20Sopenharmony_ci "tx_ppp6_frames ", 708c2ecf20Sopenharmony_ci "tx_ppp7_frames ", 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci "rx_octets_ok ", 738c2ecf20Sopenharmony_ci "rx_frames_ok ", 748c2ecf20Sopenharmony_ci "rx_broadcast_frames ", 758c2ecf20Sopenharmony_ci "rx_multicast_frames ", 768c2ecf20Sopenharmony_ci "rx_unicast_frames ", 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci "rx_frames_too_long ", 798c2ecf20Sopenharmony_ci "rx_jabber_errors ", 808c2ecf20Sopenharmony_ci "rx_fcs_errors ", 818c2ecf20Sopenharmony_ci "rx_length_errors ", 828c2ecf20Sopenharmony_ci "rx_symbol_errors ", 838c2ecf20Sopenharmony_ci "rx_runt_frames ", 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci "rx_frames_64 ", 868c2ecf20Sopenharmony_ci "rx_frames_65_to_127 ", 878c2ecf20Sopenharmony_ci "rx_frames_128_to_255 ", 888c2ecf20Sopenharmony_ci "rx_frames_256_to_511 ", 898c2ecf20Sopenharmony_ci "rx_frames_512_to_1023 ", 908c2ecf20Sopenharmony_ci "rx_frames_1024_to_1518 ", 918c2ecf20Sopenharmony_ci "rx_frames_1519_to_max ", 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci "rx_pause_frames ", 948c2ecf20Sopenharmony_ci "rx_ppp0_frames ", 958c2ecf20Sopenharmony_ci "rx_ppp1_frames ", 968c2ecf20Sopenharmony_ci "rx_ppp2_frames ", 978c2ecf20Sopenharmony_ci "rx_ppp3_frames ", 988c2ecf20Sopenharmony_ci "rx_ppp4_frames ", 998c2ecf20Sopenharmony_ci "rx_ppp5_frames ", 1008c2ecf20Sopenharmony_ci "rx_ppp6_frames ", 1018c2ecf20Sopenharmony_ci "rx_ppp7_frames ", 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci "rx_bg0_frames_dropped ", 1048c2ecf20Sopenharmony_ci "rx_bg1_frames_dropped ", 1058c2ecf20Sopenharmony_ci "rx_bg2_frames_dropped ", 1068c2ecf20Sopenharmony_ci "rx_bg3_frames_dropped ", 1078c2ecf20Sopenharmony_ci "rx_bg0_frames_trunc ", 1088c2ecf20Sopenharmony_ci "rx_bg1_frames_trunc ", 1098c2ecf20Sopenharmony_ci "rx_bg2_frames_trunc ", 1108c2ecf20Sopenharmony_ci "rx_bg3_frames_trunc ", 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci "tso ", 1138c2ecf20Sopenharmony_ci "uso ", 1148c2ecf20Sopenharmony_ci "tx_csum_offload ", 1158c2ecf20Sopenharmony_ci "rx_csum_good ", 1168c2ecf20Sopenharmony_ci "vlan_extractions ", 1178c2ecf20Sopenharmony_ci "vlan_insertions ", 1188c2ecf20Sopenharmony_ci "gro_packets ", 1198c2ecf20Sopenharmony_ci "gro_merged ", 1208c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 1218c2ecf20Sopenharmony_ci "tx_tls_encrypted_packets", 1228c2ecf20Sopenharmony_ci "tx_tls_encrypted_bytes ", 1238c2ecf20Sopenharmony_ci "tx_tls_ctx ", 1248c2ecf20Sopenharmony_ci "tx_tls_ooo ", 1258c2ecf20Sopenharmony_ci "tx_tls_skip_no_sync_data", 1268c2ecf20Sopenharmony_ci "tx_tls_drop_no_sync_data", 1278c2ecf20Sopenharmony_ci "tx_tls_drop_bypass_req ", 1288c2ecf20Sopenharmony_ci#endif 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic char adapter_stats_strings[][ETH_GSTRING_LEN] = { 1328c2ecf20Sopenharmony_ci "db_drop ", 1338c2ecf20Sopenharmony_ci "db_full ", 1348c2ecf20Sopenharmony_ci "db_empty ", 1358c2ecf20Sopenharmony_ci "write_coal_success ", 1368c2ecf20Sopenharmony_ci "write_coal_fail ", 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic char loopback_stats_strings[][ETH_GSTRING_LEN] = { 1408c2ecf20Sopenharmony_ci "-------Loopback----------- ", 1418c2ecf20Sopenharmony_ci "octets_ok ", 1428c2ecf20Sopenharmony_ci "frames_ok ", 1438c2ecf20Sopenharmony_ci "bcast_frames ", 1448c2ecf20Sopenharmony_ci "mcast_frames ", 1458c2ecf20Sopenharmony_ci "ucast_frames ", 1468c2ecf20Sopenharmony_ci "error_frames ", 1478c2ecf20Sopenharmony_ci "frames_64 ", 1488c2ecf20Sopenharmony_ci "frames_65_to_127 ", 1498c2ecf20Sopenharmony_ci "frames_128_to_255 ", 1508c2ecf20Sopenharmony_ci "frames_256_to_511 ", 1518c2ecf20Sopenharmony_ci "frames_512_to_1023 ", 1528c2ecf20Sopenharmony_ci "frames_1024_to_1518 ", 1538c2ecf20Sopenharmony_ci "frames_1519_to_max ", 1548c2ecf20Sopenharmony_ci "frames_dropped ", 1558c2ecf20Sopenharmony_ci "bg0_frames_dropped ", 1568c2ecf20Sopenharmony_ci "bg1_frames_dropped ", 1578c2ecf20Sopenharmony_ci "bg2_frames_dropped ", 1588c2ecf20Sopenharmony_ci "bg3_frames_dropped ", 1598c2ecf20Sopenharmony_ci "bg0_frames_trunc ", 1608c2ecf20Sopenharmony_ci "bg1_frames_trunc ", 1618c2ecf20Sopenharmony_ci "bg2_frames_trunc ", 1628c2ecf20Sopenharmony_ci "bg3_frames_trunc ", 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const char cxgb4_priv_flags_strings[][ETH_GSTRING_LEN] = { 1668c2ecf20Sopenharmony_ci [PRIV_FLAG_PORT_TX_VM_BIT] = "port_tx_vm_wr", 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int get_sset_count(struct net_device *dev, int sset) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci switch (sset) { 1728c2ecf20Sopenharmony_ci case ETH_SS_STATS: 1738c2ecf20Sopenharmony_ci return ARRAY_SIZE(stats_strings) + 1748c2ecf20Sopenharmony_ci ARRAY_SIZE(adapter_stats_strings) + 1758c2ecf20Sopenharmony_ci ARRAY_SIZE(loopback_stats_strings); 1768c2ecf20Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 1778c2ecf20Sopenharmony_ci return ARRAY_SIZE(cxgb4_priv_flags_strings); 1788c2ecf20Sopenharmony_ci case ETH_SS_TEST: 1798c2ecf20Sopenharmony_ci return ARRAY_SIZE(cxgb4_selftest_strings); 1808c2ecf20Sopenharmony_ci default: 1818c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int get_regs_len(struct net_device *dev) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return t4_get_regs_len(adap); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int get_eeprom_len(struct net_device *dev) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci return EEPROMSIZE; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 2008c2ecf20Sopenharmony_ci u32 exprom_vers; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); 2038c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(adapter->pdev), 2048c2ecf20Sopenharmony_ci sizeof(info->bus_info)); 2058c2ecf20Sopenharmony_ci info->regdump_len = get_regs_len(dev); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (adapter->params.fw_vers) 2088c2ecf20Sopenharmony_ci snprintf(info->fw_version, sizeof(info->fw_version), 2098c2ecf20Sopenharmony_ci "%u.%u.%u.%u, TP %u.%u.%u.%u", 2108c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), 2118c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), 2128c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), 2138c2ecf20Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), 2148c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), 2158c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), 2168c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), 2178c2ecf20Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (!t4_get_exprom_version(adapter, &exprom_vers)) 2208c2ecf20Sopenharmony_ci snprintf(info->erom_version, sizeof(info->erom_version), 2218c2ecf20Sopenharmony_ci "%u.%u.%u.%u", 2228c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MAJOR_G(exprom_vers), 2238c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MINOR_G(exprom_vers), 2248c2ecf20Sopenharmony_ci FW_HDR_FW_VER_MICRO_G(exprom_vers), 2258c2ecf20Sopenharmony_ci FW_HDR_FW_VER_BUILD_G(exprom_vers)); 2268c2ecf20Sopenharmony_ci info->n_priv_flags = ARRAY_SIZE(cxgb4_priv_flags_strings); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void get_strings(struct net_device *dev, u32 stringset, u8 *data) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci if (stringset == ETH_SS_STATS) { 2328c2ecf20Sopenharmony_ci memcpy(data, stats_strings, sizeof(stats_strings)); 2338c2ecf20Sopenharmony_ci data += sizeof(stats_strings); 2348c2ecf20Sopenharmony_ci memcpy(data, adapter_stats_strings, 2358c2ecf20Sopenharmony_ci sizeof(adapter_stats_strings)); 2368c2ecf20Sopenharmony_ci data += sizeof(adapter_stats_strings); 2378c2ecf20Sopenharmony_ci memcpy(data, loopback_stats_strings, 2388c2ecf20Sopenharmony_ci sizeof(loopback_stats_strings)); 2398c2ecf20Sopenharmony_ci } else if (stringset == ETH_SS_PRIV_FLAGS) { 2408c2ecf20Sopenharmony_ci memcpy(data, cxgb4_priv_flags_strings, 2418c2ecf20Sopenharmony_ci sizeof(cxgb4_priv_flags_strings)); 2428c2ecf20Sopenharmony_ci } else if (stringset == ETH_SS_TEST) { 2438c2ecf20Sopenharmony_ci memcpy(data, cxgb4_selftest_strings, 2448c2ecf20Sopenharmony_ci sizeof(cxgb4_selftest_strings)); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* port stats maintained per queue of the port. They should be in the same 2498c2ecf20Sopenharmony_ci * order as in stats_strings above. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistruct queue_port_stats { 2528c2ecf20Sopenharmony_ci u64 tso; 2538c2ecf20Sopenharmony_ci u64 uso; 2548c2ecf20Sopenharmony_ci u64 tx_csum; 2558c2ecf20Sopenharmony_ci u64 rx_csum; 2568c2ecf20Sopenharmony_ci u64 vlan_ex; 2578c2ecf20Sopenharmony_ci u64 vlan_ins; 2588c2ecf20Sopenharmony_ci u64 gro_pkts; 2598c2ecf20Sopenharmony_ci u64 gro_merged; 2608c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 2618c2ecf20Sopenharmony_ci u64 tx_tls_encrypted_packets; 2628c2ecf20Sopenharmony_ci u64 tx_tls_encrypted_bytes; 2638c2ecf20Sopenharmony_ci u64 tx_tls_ctx; 2648c2ecf20Sopenharmony_ci u64 tx_tls_ooo; 2658c2ecf20Sopenharmony_ci u64 tx_tls_skip_no_sync_data; 2668c2ecf20Sopenharmony_ci u64 tx_tls_drop_no_sync_data; 2678c2ecf20Sopenharmony_ci u64 tx_tls_drop_bypass_req; 2688c2ecf20Sopenharmony_ci#endif 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistruct adapter_stats { 2728c2ecf20Sopenharmony_ci u64 db_drop; 2738c2ecf20Sopenharmony_ci u64 db_full; 2748c2ecf20Sopenharmony_ci u64 db_empty; 2758c2ecf20Sopenharmony_ci u64 wc_success; 2768c2ecf20Sopenharmony_ci u64 wc_fail; 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void collect_sge_port_stats(const struct adapter *adap, 2808c2ecf20Sopenharmony_ci const struct port_info *p, 2818c2ecf20Sopenharmony_ci struct queue_port_stats *s) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; 2848c2ecf20Sopenharmony_ci const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; 2858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 2868c2ecf20Sopenharmony_ci const struct ch_ktls_port_stats_debug *ktls_stats; 2878c2ecf20Sopenharmony_ci#endif 2888c2ecf20Sopenharmony_ci struct sge_eohw_txq *eohw_tx; 2898c2ecf20Sopenharmony_ci unsigned int i; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci memset(s, 0, sizeof(*s)); 2928c2ecf20Sopenharmony_ci for (i = 0; i < p->nqsets; i++, rx++, tx++) { 2938c2ecf20Sopenharmony_ci s->tso += tx->tso; 2948c2ecf20Sopenharmony_ci s->uso += tx->uso; 2958c2ecf20Sopenharmony_ci s->tx_csum += tx->tx_cso; 2968c2ecf20Sopenharmony_ci s->rx_csum += rx->stats.rx_cso; 2978c2ecf20Sopenharmony_ci s->vlan_ex += rx->stats.vlan_ex; 2988c2ecf20Sopenharmony_ci s->vlan_ins += tx->vlan_ins; 2998c2ecf20Sopenharmony_ci s->gro_pkts += rx->stats.lro_pkts; 3008c2ecf20Sopenharmony_ci s->gro_merged += rx->stats.lro_merged; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (adap->sge.eohw_txq) { 3048c2ecf20Sopenharmony_ci eohw_tx = &adap->sge.eohw_txq[p->first_qset]; 3058c2ecf20Sopenharmony_ci for (i = 0; i < p->nqsets; i++, eohw_tx++) { 3068c2ecf20Sopenharmony_ci s->tso += eohw_tx->tso; 3078c2ecf20Sopenharmony_ci s->uso += eohw_tx->uso; 3088c2ecf20Sopenharmony_ci s->tx_csum += eohw_tx->tx_cso; 3098c2ecf20Sopenharmony_ci s->vlan_ins += eohw_tx->vlan_ins; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 3138c2ecf20Sopenharmony_ci ktls_stats = &adap->ch_ktls_stats.ktls_port[p->port_id]; 3148c2ecf20Sopenharmony_ci s->tx_tls_encrypted_packets = 3158c2ecf20Sopenharmony_ci atomic64_read(&ktls_stats->ktls_tx_encrypted_packets); 3168c2ecf20Sopenharmony_ci s->tx_tls_encrypted_bytes = 3178c2ecf20Sopenharmony_ci atomic64_read(&ktls_stats->ktls_tx_encrypted_bytes); 3188c2ecf20Sopenharmony_ci s->tx_tls_ctx = atomic64_read(&ktls_stats->ktls_tx_ctx); 3198c2ecf20Sopenharmony_ci s->tx_tls_ooo = atomic64_read(&ktls_stats->ktls_tx_ooo); 3208c2ecf20Sopenharmony_ci s->tx_tls_skip_no_sync_data = 3218c2ecf20Sopenharmony_ci atomic64_read(&ktls_stats->ktls_tx_skip_no_sync_data); 3228c2ecf20Sopenharmony_ci s->tx_tls_drop_no_sync_data = 3238c2ecf20Sopenharmony_ci atomic64_read(&ktls_stats->ktls_tx_drop_no_sync_data); 3248c2ecf20Sopenharmony_ci s->tx_tls_drop_bypass_req = 3258c2ecf20Sopenharmony_ci atomic64_read(&ktls_stats->ktls_tx_drop_bypass_req); 3268c2ecf20Sopenharmony_ci#endif 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci u64 val1, val2; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci memset(s, 0, sizeof(*s)); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci s->db_drop = adap->db_stats.db_drop; 3368c2ecf20Sopenharmony_ci s->db_full = adap->db_stats.db_full; 3378c2ecf20Sopenharmony_ci s->db_empty = adap->db_stats.db_empty; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!is_t4(adap->params.chip)) { 3408c2ecf20Sopenharmony_ci int v; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci v = t4_read_reg(adap, SGE_STAT_CFG_A); 3438c2ecf20Sopenharmony_ci if (STATSOURCE_T5_G(v) == 7) { 3448c2ecf20Sopenharmony_ci val2 = t4_read_reg(adap, SGE_STAT_MATCH_A); 3458c2ecf20Sopenharmony_ci val1 = t4_read_reg(adap, SGE_STAT_TOTAL_A); 3468c2ecf20Sopenharmony_ci s->wc_success = val1 - val2; 3478c2ecf20Sopenharmony_ci s->wc_fail = val2; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void get_stats(struct net_device *dev, struct ethtool_stats *stats, 3538c2ecf20Sopenharmony_ci u64 *data) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 3568c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 3578c2ecf20Sopenharmony_ci struct lb_port_stats s; 3588c2ecf20Sopenharmony_ci int i; 3598c2ecf20Sopenharmony_ci u64 *p0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci t4_get_port_stats_offset(adapter, pi->tx_chan, 3628c2ecf20Sopenharmony_ci (struct port_stats *)data, 3638c2ecf20Sopenharmony_ci &pi->stats_base); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci data += sizeof(struct port_stats) / sizeof(u64); 3668c2ecf20Sopenharmony_ci collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); 3678c2ecf20Sopenharmony_ci data += sizeof(struct queue_port_stats) / sizeof(u64); 3688c2ecf20Sopenharmony_ci collect_adapter_stats(adapter, (struct adapter_stats *)data); 3698c2ecf20Sopenharmony_ci data += sizeof(struct adapter_stats) / sizeof(u64); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci *data++ = (u64)pi->port_id; 3728c2ecf20Sopenharmony_ci memset(&s, 0, sizeof(s)); 3738c2ecf20Sopenharmony_ci t4_get_lb_stats(adapter, pi->port_id, &s); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci p0 = &s.octets; 3768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(loopback_stats_strings) - 1; i++) 3778c2ecf20Sopenharmony_ci *data++ = (unsigned long long)*p0++; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void get_regs(struct net_device *dev, struct ethtool_regs *regs, 3818c2ecf20Sopenharmony_ci void *buf) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 3848c2ecf20Sopenharmony_ci size_t buf_size; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci buf_size = t4_get_regs_len(adap); 3878c2ecf20Sopenharmony_ci regs->version = mk_adap_vers(adap); 3888c2ecf20Sopenharmony_ci t4_get_regs(adap, buf, buf_size); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int restart_autoneg(struct net_device *dev) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct port_info *p = netdev_priv(dev); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (!netif_running(dev)) 3968c2ecf20Sopenharmony_ci return -EAGAIN; 3978c2ecf20Sopenharmony_ci if (p->link_cfg.autoneg != AUTONEG_ENABLE) 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci t4_restart_aneg(p->adapter, p->adapter->pf, p->tx_chan); 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int identify_port(struct net_device *dev, 4048c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci unsigned int val; 4078c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (state == ETHTOOL_ID_ACTIVE) 4108c2ecf20Sopenharmony_ci val = 0xffff; 4118c2ecf20Sopenharmony_ci else if (state == ETHTOOL_ID_INACTIVE) 4128c2ecf20Sopenharmony_ci val = 0; 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return t4_identify_port(adap, adap->pf, netdev2pinfo(dev)->viid, val); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/** 4208c2ecf20Sopenharmony_ci * from_fw_port_mod_type - translate Firmware Port/Module type to Ethtool 4218c2ecf20Sopenharmony_ci * @port_type: Firmware Port Type 4228c2ecf20Sopenharmony_ci * @mod_type: Firmware Module Type 4238c2ecf20Sopenharmony_ci * 4248c2ecf20Sopenharmony_ci * Translate Firmware Port/Module type to Ethtool Port Type. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_cistatic int from_fw_port_mod_type(enum fw_port_type port_type, 4278c2ecf20Sopenharmony_ci enum fw_port_module_type mod_type) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci if (port_type == FW_PORT_TYPE_BT_SGMII || 4308c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_BT_XFI || 4318c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_BT_XAUI) { 4328c2ecf20Sopenharmony_ci return PORT_TP; 4338c2ecf20Sopenharmony_ci } else if (port_type == FW_PORT_TYPE_FIBER_XFI || 4348c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_FIBER_XAUI) { 4358c2ecf20Sopenharmony_ci return PORT_FIBRE; 4368c2ecf20Sopenharmony_ci } else if (port_type == FW_PORT_TYPE_SFP || 4378c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_QSFP_10G || 4388c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_QSA || 4398c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_QSFP || 4408c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_CR4_QSFP || 4418c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_CR_QSFP || 4428c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_CR2_QSFP || 4438c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_SFP28) { 4448c2ecf20Sopenharmony_ci if (mod_type == FW_PORT_MOD_TYPE_LR || 4458c2ecf20Sopenharmony_ci mod_type == FW_PORT_MOD_TYPE_SR || 4468c2ecf20Sopenharmony_ci mod_type == FW_PORT_MOD_TYPE_ER || 4478c2ecf20Sopenharmony_ci mod_type == FW_PORT_MOD_TYPE_LRM) 4488c2ecf20Sopenharmony_ci return PORT_FIBRE; 4498c2ecf20Sopenharmony_ci else if (mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || 4508c2ecf20Sopenharmony_ci mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) 4518c2ecf20Sopenharmony_ci return PORT_DA; 4528c2ecf20Sopenharmony_ci else 4538c2ecf20Sopenharmony_ci return PORT_OTHER; 4548c2ecf20Sopenharmony_ci } else if (port_type == FW_PORT_TYPE_KR4_100G || 4558c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_KR_SFP28 || 4568c2ecf20Sopenharmony_ci port_type == FW_PORT_TYPE_KR_XLAUI) { 4578c2ecf20Sopenharmony_ci return PORT_NONE; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return PORT_OTHER; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/** 4648c2ecf20Sopenharmony_ci * speed_to_fw_caps - translate Port Speed to Firmware Port Capabilities 4658c2ecf20Sopenharmony_ci * @speed: speed in Kb/s 4668c2ecf20Sopenharmony_ci * 4678c2ecf20Sopenharmony_ci * Translates a specific Port Speed into a Firmware Port Capabilities 4688c2ecf20Sopenharmony_ci * value. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_cistatic unsigned int speed_to_fw_caps(int speed) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci if (speed == 100) 4738c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_100M; 4748c2ecf20Sopenharmony_ci if (speed == 1000) 4758c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_1G; 4768c2ecf20Sopenharmony_ci if (speed == 10000) 4778c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_10G; 4788c2ecf20Sopenharmony_ci if (speed == 25000) 4798c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_25G; 4808c2ecf20Sopenharmony_ci if (speed == 40000) 4818c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_40G; 4828c2ecf20Sopenharmony_ci if (speed == 50000) 4838c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_50G; 4848c2ecf20Sopenharmony_ci if (speed == 100000) 4858c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_100G; 4868c2ecf20Sopenharmony_ci if (speed == 200000) 4878c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_200G; 4888c2ecf20Sopenharmony_ci if (speed == 400000) 4898c2ecf20Sopenharmony_ci return FW_PORT_CAP32_SPEED_400G; 4908c2ecf20Sopenharmony_ci return 0; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/** 4948c2ecf20Sopenharmony_ci * fw_caps_to_lmm - translate Firmware to ethtool Link Mode Mask 4958c2ecf20Sopenharmony_ci * @port_type: Firmware Port Type 4968c2ecf20Sopenharmony_ci * @fw_caps: Firmware Port Capabilities 4978c2ecf20Sopenharmony_ci * @link_mode_mask: ethtool Link Mode Mask 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * Translate a Firmware Port Capabilities specification to an ethtool 5008c2ecf20Sopenharmony_ci * Link Mode Mask. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic void fw_caps_to_lmm(enum fw_port_type port_type, 5038c2ecf20Sopenharmony_ci fw_port_cap32_t fw_caps, 5048c2ecf20Sopenharmony_ci unsigned long *link_mode_mask) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci #define SET_LMM(__lmm_name) \ 5078c2ecf20Sopenharmony_ci do { \ 5088c2ecf20Sopenharmony_ci __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ 5098c2ecf20Sopenharmony_ci link_mode_mask); \ 5108c2ecf20Sopenharmony_ci } while (0) 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci #define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \ 5138c2ecf20Sopenharmony_ci do { \ 5148c2ecf20Sopenharmony_ci if (fw_caps & FW_PORT_CAP32_ ## __fw_name) \ 5158c2ecf20Sopenharmony_ci SET_LMM(__lmm_name); \ 5168c2ecf20Sopenharmony_ci } while (0) 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci switch (port_type) { 5198c2ecf20Sopenharmony_ci case FW_PORT_TYPE_BT_SGMII: 5208c2ecf20Sopenharmony_ci case FW_PORT_TYPE_BT_XFI: 5218c2ecf20Sopenharmony_ci case FW_PORT_TYPE_BT_XAUI: 5228c2ecf20Sopenharmony_ci SET_LMM(TP); 5238c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_100M, 100baseT_Full); 5248c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5258c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 5268c2ecf20Sopenharmony_ci break; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci case FW_PORT_TYPE_KX4: 5298c2ecf20Sopenharmony_ci case FW_PORT_TYPE_KX: 5308c2ecf20Sopenharmony_ci SET_LMM(Backplane); 5318c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 5328c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKX4_Full); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci case FW_PORT_TYPE_KR: 5368c2ecf20Sopenharmony_ci SET_LMM(Backplane); 5378c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci case FW_PORT_TYPE_BP_AP: 5418c2ecf20Sopenharmony_ci SET_LMM(Backplane); 5428c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 5438c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseR_FEC); 5448c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci case FW_PORT_TYPE_BP4_AP: 5488c2ecf20Sopenharmony_ci SET_LMM(Backplane); 5498c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 5508c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseR_FEC); 5518c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 5528c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKX4_Full); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci case FW_PORT_TYPE_FIBER_XFI: 5568c2ecf20Sopenharmony_ci case FW_PORT_TYPE_FIBER_XAUI: 5578c2ecf20Sopenharmony_ci case FW_PORT_TYPE_SFP: 5588c2ecf20Sopenharmony_ci case FW_PORT_TYPE_QSFP_10G: 5598c2ecf20Sopenharmony_ci case FW_PORT_TYPE_QSA: 5608c2ecf20Sopenharmony_ci SET_LMM(FIBRE); 5618c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5628c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 5638c2ecf20Sopenharmony_ci break; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci case FW_PORT_TYPE_BP40_BA: 5668c2ecf20Sopenharmony_ci case FW_PORT_TYPE_QSFP: 5678c2ecf20Sopenharmony_ci SET_LMM(FIBRE); 5688c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5698c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 5708c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full); 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci case FW_PORT_TYPE_CR_QSFP: 5748c2ecf20Sopenharmony_ci case FW_PORT_TYPE_SFP28: 5758c2ecf20Sopenharmony_ci SET_LMM(FIBRE); 5768c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5778c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 5788c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci case FW_PORT_TYPE_KR_SFP28: 5828c2ecf20Sopenharmony_ci SET_LMM(Backplane); 5838c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5848c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 5858c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full); 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci case FW_PORT_TYPE_KR_XLAUI: 5898c2ecf20Sopenharmony_ci SET_LMM(Backplane); 5908c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 5918c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 5928c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_40G, 40000baseKR4_Full); 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci case FW_PORT_TYPE_CR2_QSFP: 5968c2ecf20Sopenharmony_ci SET_LMM(FIBRE); 5978c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_50G, 50000baseSR2_Full); 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci case FW_PORT_TYPE_KR4_100G: 6018c2ecf20Sopenharmony_ci case FW_PORT_TYPE_CR4_QSFP: 6028c2ecf20Sopenharmony_ci SET_LMM(FIBRE); 6038c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 6048c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 6058c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full); 6068c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); 6078c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_50G, 50000baseCR2_Full); 6088c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(SPEED_100G, 100000baseCR4_Full); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci default: 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (fw_caps & FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M)) { 6168c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(FEC_RS, FEC_RS); 6178c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(FEC_BASER_RS, FEC_BASER); 6188c2ecf20Sopenharmony_ci } else { 6198c2ecf20Sopenharmony_ci SET_LMM(FEC_NONE); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(ANEG, Autoneg); 6238c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(802_3_PAUSE, Pause); 6248c2ecf20Sopenharmony_ci FW_CAPS_TO_LMM(802_3_ASM_DIR, Asym_Pause); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci #undef FW_CAPS_TO_LMM 6278c2ecf20Sopenharmony_ci #undef SET_LMM 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/** 6318c2ecf20Sopenharmony_ci * lmm_to_fw_caps - translate ethtool Link Mode Mask to Firmware 6328c2ecf20Sopenharmony_ci * capabilities 6338c2ecf20Sopenharmony_ci * @link_mode_mask: ethtool Link Mode Mask 6348c2ecf20Sopenharmony_ci * 6358c2ecf20Sopenharmony_ci * Translate ethtool Link Mode Mask into a Firmware Port capabilities 6368c2ecf20Sopenharmony_ci * value. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_cistatic unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci unsigned int fw_caps = 0; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci #define LMM_TO_FW_CAPS(__lmm_name, __fw_name) \ 6438c2ecf20Sopenharmony_ci do { \ 6448c2ecf20Sopenharmony_ci if (test_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ 6458c2ecf20Sopenharmony_ci link_mode_mask)) \ 6468c2ecf20Sopenharmony_ci fw_caps |= FW_PORT_CAP32_ ## __fw_name; \ 6478c2ecf20Sopenharmony_ci } while (0) 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(100baseT_Full, SPEED_100M); 6508c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(1000baseT_Full, SPEED_1G); 6518c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(10000baseT_Full, SPEED_10G); 6528c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(40000baseSR4_Full, SPEED_40G); 6538c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(25000baseCR_Full, SPEED_25G); 6548c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(50000baseCR2_Full, SPEED_50G); 6558c2ecf20Sopenharmony_ci LMM_TO_FW_CAPS(100000baseCR4_Full, SPEED_100G); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci #undef LMM_TO_FW_CAPS 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return fw_caps; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int get_link_ksettings(struct net_device *dev, 6638c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *link_ksettings) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 6668c2ecf20Sopenharmony_ci struct ethtool_link_settings *base = &link_ksettings->base; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* For the nonce, the Firmware doesn't send up Port State changes 6698c2ecf20Sopenharmony_ci * when the Virtual Interface attached to the Port is down. So 6708c2ecf20Sopenharmony_ci * if it's down, let's grab any changes. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci if (!netif_running(dev)) 6738c2ecf20Sopenharmony_ci (void)t4_update_port_info(pi); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 6768c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 6778c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (pi->mdio_addr >= 0) { 6828c2ecf20Sopenharmony_ci base->phy_address = pi->mdio_addr; 6838c2ecf20Sopenharmony_ci base->mdio_support = (pi->port_type == FW_PORT_TYPE_BT_SGMII 6848c2ecf20Sopenharmony_ci ? ETH_MDIO_SUPPORTS_C22 6858c2ecf20Sopenharmony_ci : ETH_MDIO_SUPPORTS_C45); 6868c2ecf20Sopenharmony_ci } else { 6878c2ecf20Sopenharmony_ci base->phy_address = 255; 6888c2ecf20Sopenharmony_ci base->mdio_support = 0; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci fw_caps_to_lmm(pi->port_type, pi->link_cfg.pcaps, 6928c2ecf20Sopenharmony_ci link_ksettings->link_modes.supported); 6938c2ecf20Sopenharmony_ci fw_caps_to_lmm(pi->port_type, 6948c2ecf20Sopenharmony_ci t4_link_acaps(pi->adapter, 6958c2ecf20Sopenharmony_ci pi->lport, 6968c2ecf20Sopenharmony_ci &pi->link_cfg), 6978c2ecf20Sopenharmony_ci link_ksettings->link_modes.advertising); 6988c2ecf20Sopenharmony_ci fw_caps_to_lmm(pi->port_type, pi->link_cfg.lpacaps, 6998c2ecf20Sopenharmony_ci link_ksettings->link_modes.lp_advertising); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci base->speed = (netif_carrier_ok(dev) 7028c2ecf20Sopenharmony_ci ? pi->link_cfg.speed 7038c2ecf20Sopenharmony_ci : SPEED_UNKNOWN); 7048c2ecf20Sopenharmony_ci base->duplex = DUPLEX_FULL; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci base->autoneg = pi->link_cfg.autoneg; 7078c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG) 7088c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 7098c2ecf20Sopenharmony_ci supported, Autoneg); 7108c2ecf20Sopenharmony_ci if (pi->link_cfg.autoneg) 7118c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(link_ksettings, 7128c2ecf20Sopenharmony_ci advertising, Autoneg); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int set_link_ksettings(struct net_device *dev, 7188c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *link_ksettings) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 7218c2ecf20Sopenharmony_ci struct link_config *lc = &pi->link_cfg; 7228c2ecf20Sopenharmony_ci const struct ethtool_link_settings *base = &link_ksettings->base; 7238c2ecf20Sopenharmony_ci struct link_config old_lc; 7248c2ecf20Sopenharmony_ci unsigned int fw_caps; 7258c2ecf20Sopenharmony_ci int ret = 0; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* only full-duplex supported */ 7288c2ecf20Sopenharmony_ci if (base->duplex != DUPLEX_FULL) 7298c2ecf20Sopenharmony_ci return -EINVAL; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci old_lc = *lc; 7328c2ecf20Sopenharmony_ci if (!(lc->pcaps & FW_PORT_CAP32_ANEG) || 7338c2ecf20Sopenharmony_ci base->autoneg == AUTONEG_DISABLE) { 7348c2ecf20Sopenharmony_ci fw_caps = speed_to_fw_caps(base->speed); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Speed must be supported by Physical Port Capabilities. */ 7378c2ecf20Sopenharmony_ci if (!(lc->pcaps & fw_caps)) 7388c2ecf20Sopenharmony_ci return -EINVAL; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci lc->speed_caps = fw_caps; 7418c2ecf20Sopenharmony_ci lc->acaps = fw_caps; 7428c2ecf20Sopenharmony_ci } else { 7438c2ecf20Sopenharmony_ci fw_caps = 7448c2ecf20Sopenharmony_ci lmm_to_fw_caps(link_ksettings->link_modes.advertising); 7458c2ecf20Sopenharmony_ci if (!(lc->pcaps & fw_caps)) 7468c2ecf20Sopenharmony_ci return -EINVAL; 7478c2ecf20Sopenharmony_ci lc->speed_caps = 0; 7488c2ecf20Sopenharmony_ci lc->acaps = fw_caps | FW_PORT_CAP32_ANEG; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci lc->autoneg = base->autoneg; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* If the firmware rejects the Link Configuration request, back out 7538c2ecf20Sopenharmony_ci * the changes and report the error. 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox, pi->tx_chan, lc); 7568c2ecf20Sopenharmony_ci if (ret) 7578c2ecf20Sopenharmony_ci *lc = old_lc; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci/* Translate the Firmware FEC value into the ethtool value. */ 7638c2ecf20Sopenharmony_cistatic inline unsigned int fwcap_to_eth_fec(unsigned int fw_fec) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci unsigned int eth_fec = 0; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (fw_fec & FW_PORT_CAP32_FEC_RS) 7688c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_RS; 7698c2ecf20Sopenharmony_ci if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS) 7708c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_BASER; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* if nothing is set, then FEC is off */ 7738c2ecf20Sopenharmony_ci if (!eth_fec) 7748c2ecf20Sopenharmony_ci eth_fec = ETHTOOL_FEC_OFF; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return eth_fec; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci/* Translate Common Code FEC value into ethtool value. */ 7808c2ecf20Sopenharmony_cistatic inline unsigned int cc_to_eth_fec(unsigned int cc_fec) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci unsigned int eth_fec = 0; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (cc_fec & FEC_AUTO) 7858c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_AUTO; 7868c2ecf20Sopenharmony_ci if (cc_fec & FEC_RS) 7878c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_RS; 7888c2ecf20Sopenharmony_ci if (cc_fec & FEC_BASER_RS) 7898c2ecf20Sopenharmony_ci eth_fec |= ETHTOOL_FEC_BASER; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* if nothing is set, then FEC is off */ 7928c2ecf20Sopenharmony_ci if (!eth_fec) 7938c2ecf20Sopenharmony_ci eth_fec = ETHTOOL_FEC_OFF; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return eth_fec; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/* Translate ethtool FEC value into Common Code value. */ 7998c2ecf20Sopenharmony_cistatic inline unsigned int eth_to_cc_fec(unsigned int eth_fec) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci unsigned int cc_fec = 0; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_OFF) 8048c2ecf20Sopenharmony_ci return cc_fec; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_AUTO) 8078c2ecf20Sopenharmony_ci cc_fec |= FEC_AUTO; 8088c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_RS) 8098c2ecf20Sopenharmony_ci cc_fec |= FEC_RS; 8108c2ecf20Sopenharmony_ci if (eth_fec & ETHTOOL_FEC_BASER) 8118c2ecf20Sopenharmony_ci cc_fec |= FEC_BASER_RS; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return cc_fec; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic int get_fecparam(struct net_device *dev, struct ethtool_fecparam *fec) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 8198c2ecf20Sopenharmony_ci const struct link_config *lc = &pi->link_cfg; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* Translate the Firmware FEC Support into the ethtool value. We 8228c2ecf20Sopenharmony_ci * always support IEEE 802.3 "automatic" selection of Link FEC type if 8238c2ecf20Sopenharmony_ci * any FEC is supported. 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ci fec->fec = fwcap_to_eth_fec(lc->pcaps); 8268c2ecf20Sopenharmony_ci if (fec->fec != ETHTOOL_FEC_OFF) 8278c2ecf20Sopenharmony_ci fec->fec |= ETHTOOL_FEC_AUTO; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* Translate the current internal FEC parameters into the 8308c2ecf20Sopenharmony_ci * ethtool values. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_ci fec->active_fec = cc_to_eth_fec(lc->fec); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int set_fecparam(struct net_device *dev, struct ethtool_fecparam *fec) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 8408c2ecf20Sopenharmony_ci struct link_config *lc = &pi->link_cfg; 8418c2ecf20Sopenharmony_ci struct link_config old_lc; 8428c2ecf20Sopenharmony_ci int ret; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Save old Link Configuration in case the L1 Configure below 8458c2ecf20Sopenharmony_ci * fails. 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_ci old_lc = *lc; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* Try to perform the L1 Configure and return the result of that 8508c2ecf20Sopenharmony_ci * effort. If it fails, revert the attempted change. 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_ci lc->requested_fec = eth_to_cc_fec(fec->fec); 8538c2ecf20Sopenharmony_ci ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox, 8548c2ecf20Sopenharmony_ci pi->tx_chan, lc); 8558c2ecf20Sopenharmony_ci if (ret) 8568c2ecf20Sopenharmony_ci *lc = old_lc; 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic void get_pauseparam(struct net_device *dev, 8618c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct port_info *p = netdev_priv(dev); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; 8668c2ecf20Sopenharmony_ci epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0; 8678c2ecf20Sopenharmony_ci epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic int set_pauseparam(struct net_device *dev, 8718c2ecf20Sopenharmony_ci struct ethtool_pauseparam *epause) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci struct port_info *p = netdev_priv(dev); 8748c2ecf20Sopenharmony_ci struct link_config *lc = &p->link_cfg; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (epause->autoneg == AUTONEG_DISABLE) 8778c2ecf20Sopenharmony_ci lc->requested_fc = 0; 8788c2ecf20Sopenharmony_ci else if (lc->pcaps & FW_PORT_CAP32_ANEG) 8798c2ecf20Sopenharmony_ci lc->requested_fc = PAUSE_AUTONEG; 8808c2ecf20Sopenharmony_ci else 8818c2ecf20Sopenharmony_ci return -EINVAL; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (epause->rx_pause) 8848c2ecf20Sopenharmony_ci lc->requested_fc |= PAUSE_RX; 8858c2ecf20Sopenharmony_ci if (epause->tx_pause) 8868c2ecf20Sopenharmony_ci lc->requested_fc |= PAUSE_TX; 8878c2ecf20Sopenharmony_ci if (netif_running(dev)) 8888c2ecf20Sopenharmony_ci return t4_link_l1cfg(p->adapter, p->adapter->mbox, p->tx_chan, 8898c2ecf20Sopenharmony_ci lc); 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 8968c2ecf20Sopenharmony_ci const struct sge *s = &pi->adapter->sge; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci e->rx_max_pending = MAX_RX_BUFFERS; 8998c2ecf20Sopenharmony_ci e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; 9008c2ecf20Sopenharmony_ci e->rx_jumbo_max_pending = 0; 9018c2ecf20Sopenharmony_ci e->tx_max_pending = MAX_TXQ_ENTRIES; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; 9048c2ecf20Sopenharmony_ci e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; 9058c2ecf20Sopenharmony_ci e->rx_jumbo_pending = 0; 9068c2ecf20Sopenharmony_ci e->tx_pending = s->ethtxq[pi->first_qset].q.size; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci int i; 9128c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 9138c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 9148c2ecf20Sopenharmony_ci struct sge *s = &adapter->sge; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || 9178c2ecf20Sopenharmony_ci e->tx_pending > MAX_TXQ_ENTRIES || 9188c2ecf20Sopenharmony_ci e->rx_mini_pending > MAX_RSPQ_ENTRIES || 9198c2ecf20Sopenharmony_ci e->rx_mini_pending < MIN_RSPQ_ENTRIES || 9208c2ecf20Sopenharmony_ci e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) 9218c2ecf20Sopenharmony_ci return -EINVAL; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FULL_INIT_DONE) 9248c2ecf20Sopenharmony_ci return -EBUSY; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci for (i = 0; i < pi->nqsets; ++i) { 9278c2ecf20Sopenharmony_ci s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; 9288c2ecf20Sopenharmony_ci s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; 9298c2ecf20Sopenharmony_ci s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci/** 9358c2ecf20Sopenharmony_ci * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! 9368c2ecf20Sopenharmony_ci * @dev: the network device 9378c2ecf20Sopenharmony_ci * @us: the hold-off time in us, or 0 to disable timer 9388c2ecf20Sopenharmony_ci * @cnt: the hold-off packet count, or 0 to disable counter 9398c2ecf20Sopenharmony_ci * 9408c2ecf20Sopenharmony_ci * Set the RX interrupt hold-off parameters for a network device. 9418c2ecf20Sopenharmony_ci */ 9428c2ecf20Sopenharmony_cistatic int set_rx_intr_params(struct net_device *dev, 9438c2ecf20Sopenharmony_ci unsigned int us, unsigned int cnt) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci int i, err; 9468c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 9478c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 9488c2ecf20Sopenharmony_ci struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci for (i = 0; i < pi->nqsets; i++, q++) { 9518c2ecf20Sopenharmony_ci err = cxgb4_set_rspq_intr_params(&q->rspq, us, cnt); 9528c2ecf20Sopenharmony_ci if (err) 9538c2ecf20Sopenharmony_ci return err; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci int i; 9618c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 9628c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 9638c2ecf20Sopenharmony_ci struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci for (i = 0; i < pi->nqsets; i++, q++) 9668c2ecf20Sopenharmony_ci q->rspq.adaptive_rx = adaptive_rx; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int get_adaptive_rx_setting(struct net_device *dev) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 9748c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 9758c2ecf20Sopenharmony_ci struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return q->rspq.adaptive_rx; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci/* Return the current global Adapter SGE Doorbell Queue Timer Tick for all 9818c2ecf20Sopenharmony_ci * Ethernet TX Queues. 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_cistatic int get_dbqtimer_tick(struct net_device *dev) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 9868c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 9898c2ecf20Sopenharmony_ci return 0; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci return adap->sge.dbqtimer_tick; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci/* Return the SGE Doorbell Queue Timer Value for the Ethernet TX Queues 9958c2ecf20Sopenharmony_ci * associated with a Network Device. 9968c2ecf20Sopenharmony_ci */ 9978c2ecf20Sopenharmony_cistatic int get_dbqtimer(struct net_device *dev) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 10008c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 10018c2ecf20Sopenharmony_ci struct sge_eth_txq *txq; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci txq = &adap->sge.ethtxq[pi->first_qset]; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* all of the TX Queues use the same Timer Index */ 10098c2ecf20Sopenharmony_ci return adap->sge.dbqtimer_val[txq->dbqtimerix]; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX 10138c2ecf20Sopenharmony_ci * Queues. This is the fundamental "Tick" that sets the scale of values which 10148c2ecf20Sopenharmony_ci * can be used. Individual Ethernet TX Queues index into a relatively small 10158c2ecf20Sopenharmony_ci * array of Tick Multipliers. Changing the base Tick will thus change all of 10168c2ecf20Sopenharmony_ci * the resulting Timer Values associated with those multipliers for all 10178c2ecf20Sopenharmony_ci * Ethernet TX Queues. 10188c2ecf20Sopenharmony_ci */ 10198c2ecf20Sopenharmony_cistatic int set_dbqtimer_tick(struct net_device *dev, int usecs) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 10228c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 10238c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 10248c2ecf20Sopenharmony_ci u32 param, val; 10258c2ecf20Sopenharmony_ci int ret; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 10288c2ecf20Sopenharmony_ci return 0; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* return early if it's the same Timer Tick we're already using */ 10318c2ecf20Sopenharmony_ci if (s->dbqtimer_tick == usecs) 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* attempt to set the new Timer Tick value */ 10358c2ecf20Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 10368c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK)); 10378c2ecf20Sopenharmony_ci val = usecs; 10388c2ecf20Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 10398c2ecf20Sopenharmony_ci if (ret) 10408c2ecf20Sopenharmony_ci return ret; 10418c2ecf20Sopenharmony_ci s->dbqtimer_tick = usecs; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* if successful, reread resulting dependent Timer values */ 10448c2ecf20Sopenharmony_ci ret = t4_read_sge_dbqtimers(adap, ARRAY_SIZE(s->dbqtimer_val), 10458c2ecf20Sopenharmony_ci s->dbqtimer_val); 10468c2ecf20Sopenharmony_ci return ret; 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci/* Set the SGE Doorbell Queue Timer Value for the Ethernet TX Queues 10508c2ecf20Sopenharmony_ci * associated with a Network Device. There is a relatively small array of 10518c2ecf20Sopenharmony_ci * possible Timer Values so we need to pick the closest value available. 10528c2ecf20Sopenharmony_ci */ 10538c2ecf20Sopenharmony_cistatic int set_dbqtimer(struct net_device *dev, int usecs) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci int qix, timerix, min_timerix, delta, min_delta; 10568c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 10578c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 10588c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 10598c2ecf20Sopenharmony_ci struct sge_eth_txq *txq; 10608c2ecf20Sopenharmony_ci u32 param, val; 10618c2ecf20Sopenharmony_ci int ret; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 10648c2ecf20Sopenharmony_ci return 0; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* Find the SGE Doorbell Timer Value that's closest to the requested 10678c2ecf20Sopenharmony_ci * value. 10688c2ecf20Sopenharmony_ci */ 10698c2ecf20Sopenharmony_ci min_delta = INT_MAX; 10708c2ecf20Sopenharmony_ci min_timerix = 0; 10718c2ecf20Sopenharmony_ci for (timerix = 0; timerix < ARRAY_SIZE(s->dbqtimer_val); timerix++) { 10728c2ecf20Sopenharmony_ci delta = s->dbqtimer_val[timerix] - usecs; 10738c2ecf20Sopenharmony_ci if (delta < 0) 10748c2ecf20Sopenharmony_ci delta = -delta; 10758c2ecf20Sopenharmony_ci if (delta < min_delta) { 10768c2ecf20Sopenharmony_ci min_delta = delta; 10778c2ecf20Sopenharmony_ci min_timerix = timerix; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Return early if it's the same Timer Index we're already using. 10828c2ecf20Sopenharmony_ci * We use the same Timer Index for all of the TX Queues for an 10838c2ecf20Sopenharmony_ci * interface so it's only necessary to check the first one. 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci txq = &s->ethtxq[pi->first_qset]; 10868c2ecf20Sopenharmony_ci if (txq->dbqtimerix == min_timerix) 10878c2ecf20Sopenharmony_ci return 0; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci for (qix = 0; qix < pi->nqsets; qix++, txq++) { 10908c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) { 10918c2ecf20Sopenharmony_ci param = 10928c2ecf20Sopenharmony_ci (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 10938c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_EQ_TIMERIX) | 10948c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id)); 10958c2ecf20Sopenharmony_ci val = min_timerix; 10968c2ecf20Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 10978c2ecf20Sopenharmony_ci 1, ¶m, &val); 10988c2ecf20Sopenharmony_ci if (ret) 10998c2ecf20Sopenharmony_ci return ret; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci txq->dbqtimerix = min_timerix; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci/* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX 11078c2ecf20Sopenharmony_ci * Queues and the Timer Value for the Ethernet TX Queues associated with a 11088c2ecf20Sopenharmony_ci * Network Device. Since changing the global Tick changes all of the 11098c2ecf20Sopenharmony_ci * available Timer Values, we need to do this first before selecting the 11108c2ecf20Sopenharmony_ci * resulting closest Timer Value. Moreover, since the Tick is global, 11118c2ecf20Sopenharmony_ci * changing it affects the Timer Values for all Network Devices on the 11128c2ecf20Sopenharmony_ci * adapter. So, before changing the Tick, we grab all of the current Timer 11138c2ecf20Sopenharmony_ci * Values for other Network Devices on this Adapter and then attempt to select 11148c2ecf20Sopenharmony_ci * new Timer Values which are close to the old values ... 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_cistatic int set_dbqtimer_tickval(struct net_device *dev, 11178c2ecf20Sopenharmony_ci int tick_usecs, int timer_usecs) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 11208c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 11218c2ecf20Sopenharmony_ci int timer[MAX_NPORTS]; 11228c2ecf20Sopenharmony_ci unsigned int port; 11238c2ecf20Sopenharmony_ci int ret; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* Grab the other adapter Network Interface current timers and fill in 11268c2ecf20Sopenharmony_ci * the new one for this Network Interface. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci for_each_port(adap, port) 11298c2ecf20Sopenharmony_ci if (port == pi->port_id) 11308c2ecf20Sopenharmony_ci timer[port] = timer_usecs; 11318c2ecf20Sopenharmony_ci else 11328c2ecf20Sopenharmony_ci timer[port] = get_dbqtimer(adap->port[port]); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Change the global Tick first ... */ 11358c2ecf20Sopenharmony_ci ret = set_dbqtimer_tick(dev, tick_usecs); 11368c2ecf20Sopenharmony_ci if (ret) 11378c2ecf20Sopenharmony_ci return ret; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* ... and then set all of the Network Interface Timer Values ... */ 11408c2ecf20Sopenharmony_ci for_each_port(adap, port) { 11418c2ecf20Sopenharmony_ci ret = set_dbqtimer(adap->port[port], timer[port]); 11428c2ecf20Sopenharmony_ci if (ret) 11438c2ecf20Sopenharmony_ci return ret; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci return 0; 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic int set_coalesce(struct net_device *dev, 11508c2ecf20Sopenharmony_ci struct ethtool_coalesce *coalesce) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci int ret; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci set_adaptive_rx_setting(dev, coalesce->use_adaptive_rx_coalesce); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci ret = set_rx_intr_params(dev, coalesce->rx_coalesce_usecs, 11578c2ecf20Sopenharmony_ci coalesce->rx_max_coalesced_frames); 11588c2ecf20Sopenharmony_ci if (ret) 11598c2ecf20Sopenharmony_ci return ret; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci return set_dbqtimer_tickval(dev, 11628c2ecf20Sopenharmony_ci coalesce->tx_coalesce_usecs_irq, 11638c2ecf20Sopenharmony_ci coalesce->tx_coalesce_usecs); 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 11698c2ecf20Sopenharmony_ci const struct adapter *adap = pi->adapter; 11708c2ecf20Sopenharmony_ci const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci c->rx_coalesce_usecs = qtimer_val(adap, rq); 11738c2ecf20Sopenharmony_ci c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ? 11748c2ecf20Sopenharmony_ci adap->sge.counter_val[rq->pktcnt_idx] : 0; 11758c2ecf20Sopenharmony_ci c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); 11768c2ecf20Sopenharmony_ci c->tx_coalesce_usecs_irq = get_dbqtimer_tick(dev); 11778c2ecf20Sopenharmony_ci c->tx_coalesce_usecs = get_dbqtimer(dev); 11788c2ecf20Sopenharmony_ci return 0; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci/* The next two routines implement eeprom read/write from physical addresses. 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_cistatic int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (vaddr >= 0) 11888c2ecf20Sopenharmony_ci vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); 11898c2ecf20Sopenharmony_ci return vaddr < 0 ? vaddr : 0; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (vaddr >= 0) 11978c2ecf20Sopenharmony_ci vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); 11988c2ecf20Sopenharmony_ci return vaddr < 0 ? vaddr : 0; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci#define EEPROM_MAGIC 0x38E2F10C 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, 12048c2ecf20Sopenharmony_ci u8 *data) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci int i, err = 0; 12078c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 12088c2ecf20Sopenharmony_ci u8 *buf = kvzalloc(EEPROMSIZE, GFP_KERNEL); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!buf) 12118c2ecf20Sopenharmony_ci return -ENOMEM; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci e->magic = EEPROM_MAGIC; 12148c2ecf20Sopenharmony_ci for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) 12158c2ecf20Sopenharmony_ci err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (!err) 12188c2ecf20Sopenharmony_ci memcpy(data, buf + e->offset, e->len); 12198c2ecf20Sopenharmony_ci kvfree(buf); 12208c2ecf20Sopenharmony_ci return err; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 12248c2ecf20Sopenharmony_ci u8 *data) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci u8 *buf; 12278c2ecf20Sopenharmony_ci int err = 0; 12288c2ecf20Sopenharmony_ci u32 aligned_offset, aligned_len, *p; 12298c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (eeprom->magic != EEPROM_MAGIC) 12328c2ecf20Sopenharmony_ci return -EINVAL; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci aligned_offset = eeprom->offset & ~3; 12358c2ecf20Sopenharmony_ci aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (adapter->pf > 0) { 12388c2ecf20Sopenharmony_ci u32 start = 1024 + adapter->pf * EEPROMPFSIZE; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (aligned_offset < start || 12418c2ecf20Sopenharmony_ci aligned_offset + aligned_len > start + EEPROMPFSIZE) 12428c2ecf20Sopenharmony_ci return -EPERM; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { 12468c2ecf20Sopenharmony_ci /* RMW possibly needed for first or last words. 12478c2ecf20Sopenharmony_ci */ 12488c2ecf20Sopenharmony_ci buf = kvzalloc(aligned_len, GFP_KERNEL); 12498c2ecf20Sopenharmony_ci if (!buf) 12508c2ecf20Sopenharmony_ci return -ENOMEM; 12518c2ecf20Sopenharmony_ci err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); 12528c2ecf20Sopenharmony_ci if (!err && aligned_len > 4) 12538c2ecf20Sopenharmony_ci err = eeprom_rd_phys(adapter, 12548c2ecf20Sopenharmony_ci aligned_offset + aligned_len - 4, 12558c2ecf20Sopenharmony_ci (u32 *)&buf[aligned_len - 4]); 12568c2ecf20Sopenharmony_ci if (err) 12578c2ecf20Sopenharmony_ci goto out; 12588c2ecf20Sopenharmony_ci memcpy(buf + (eeprom->offset & 3), data, eeprom->len); 12598c2ecf20Sopenharmony_ci } else { 12608c2ecf20Sopenharmony_ci buf = data; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci err = t4_seeprom_wp(adapter, false); 12648c2ecf20Sopenharmony_ci if (err) 12658c2ecf20Sopenharmony_ci goto out; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 12688c2ecf20Sopenharmony_ci err = eeprom_wr_phys(adapter, aligned_offset, *p); 12698c2ecf20Sopenharmony_ci aligned_offset += 4; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci if (!err) 12738c2ecf20Sopenharmony_ci err = t4_seeprom_wp(adapter, true); 12748c2ecf20Sopenharmony_ciout: 12758c2ecf20Sopenharmony_ci if (buf != data) 12768c2ecf20Sopenharmony_ci kvfree(buf); 12778c2ecf20Sopenharmony_ci return err; 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int cxgb4_ethtool_flash_bootcfg(struct net_device *netdev, 12818c2ecf20Sopenharmony_ci const u8 *data, u32 size) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 12848c2ecf20Sopenharmony_ci int ret; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci ret = t4_load_bootcfg(adap, data, size); 12878c2ecf20Sopenharmony_ci if (ret) 12888c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Failed to load boot cfg image\n"); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci return ret; 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int cxgb4_ethtool_flash_boot(struct net_device *netdev, 12948c2ecf20Sopenharmony_ci const u8 *bdata, u32 size) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 12978c2ecf20Sopenharmony_ci unsigned int offset; 12988c2ecf20Sopenharmony_ci u8 *data; 12998c2ecf20Sopenharmony_ci int ret; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci data = kmemdup(bdata, size, GFP_KERNEL); 13028c2ecf20Sopenharmony_ci if (!data) 13038c2ecf20Sopenharmony_ci return -ENOMEM; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci offset = OFFSET_G(t4_read_reg(adap, PF_REG(0, PCIE_PF_EXPROM_OFST_A))); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci ret = t4_load_boot(adap, data, offset, size); 13088c2ecf20Sopenharmony_ci if (ret) 13098c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Failed to load boot image\n"); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci kfree(data); 13128c2ecf20Sopenharmony_ci return ret; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci#define CXGB4_PHY_SIG 0x130000ea 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic int cxgb4_validate_phy_image(const u8 *data, u32 *size) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci struct cxgb4_fw_data *header; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci header = (struct cxgb4_fw_data *)data; 13228c2ecf20Sopenharmony_ci if (be32_to_cpu(header->signature) != CXGB4_PHY_SIG) 13238c2ecf20Sopenharmony_ci return -EINVAL; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci return 0; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic int cxgb4_ethtool_flash_phy(struct net_device *netdev, 13298c2ecf20Sopenharmony_ci const u8 *data, u32 size) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 13328c2ecf20Sopenharmony_ci int ret; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci ret = cxgb4_validate_phy_image(data, NULL); 13358c2ecf20Sopenharmony_ci if (ret) { 13368c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "PHY signature mismatch\n"); 13378c2ecf20Sopenharmony_ci return ret; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* We have to RESET the chip/firmware because we need the 13418c2ecf20Sopenharmony_ci * chip in uninitialized state for loading new PHY image. 13428c2ecf20Sopenharmony_ci * Otherwise, the running firmware will only store the PHY 13438c2ecf20Sopenharmony_ci * image in local RAM which will be lost after next reset. 13448c2ecf20Sopenharmony_ci */ 13458c2ecf20Sopenharmony_ci ret = t4_fw_reset(adap, adap->mbox, PIORSTMODE_F | PIORST_F); 13468c2ecf20Sopenharmony_ci if (ret < 0) { 13478c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 13488c2ecf20Sopenharmony_ci "Set FW to RESET for flashing PHY FW failed. ret: %d\n", 13498c2ecf20Sopenharmony_ci ret); 13508c2ecf20Sopenharmony_ci return ret; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci ret = t4_load_phy_fw(adap, MEMWIN_NIC, NULL, data, size); 13548c2ecf20Sopenharmony_ci if (ret < 0) { 13558c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Failed to load PHY FW. ret: %d\n", 13568c2ecf20Sopenharmony_ci ret); 13578c2ecf20Sopenharmony_ci return ret; 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci return 0; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic int cxgb4_ethtool_flash_fw(struct net_device *netdev, 13648c2ecf20Sopenharmony_ci const u8 *data, u32 size) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 13678c2ecf20Sopenharmony_ci unsigned int mbox = PCIE_FW_MASTER_M + 1; 13688c2ecf20Sopenharmony_ci int ret; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci /* If the adapter has been fully initialized then we'll go ahead and 13718c2ecf20Sopenharmony_ci * try to get the firmware's cooperation in upgrading to the new 13728c2ecf20Sopenharmony_ci * firmware image otherwise we'll try to do the entire job from the 13738c2ecf20Sopenharmony_ci * host ... and we always "force" the operation in this path. 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 13768c2ecf20Sopenharmony_ci mbox = adap->mbox; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci ret = t4_fw_upgrade(adap, mbox, data, size, 1); 13798c2ecf20Sopenharmony_ci if (ret) 13808c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 13818c2ecf20Sopenharmony_ci "Failed to flash firmware\n"); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return ret; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int cxgb4_ethtool_flash_region(struct net_device *netdev, 13878c2ecf20Sopenharmony_ci const u8 *data, u32 size, u32 region) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 13908c2ecf20Sopenharmony_ci int ret; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci switch (region) { 13938c2ecf20Sopenharmony_ci case CXGB4_ETHTOOL_FLASH_FW: 13948c2ecf20Sopenharmony_ci ret = cxgb4_ethtool_flash_fw(netdev, data, size); 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci case CXGB4_ETHTOOL_FLASH_PHY: 13978c2ecf20Sopenharmony_ci ret = cxgb4_ethtool_flash_phy(netdev, data, size); 13988c2ecf20Sopenharmony_ci break; 13998c2ecf20Sopenharmony_ci case CXGB4_ETHTOOL_FLASH_BOOT: 14008c2ecf20Sopenharmony_ci ret = cxgb4_ethtool_flash_boot(netdev, data, size); 14018c2ecf20Sopenharmony_ci break; 14028c2ecf20Sopenharmony_ci case CXGB4_ETHTOOL_FLASH_BOOTCFG: 14038c2ecf20Sopenharmony_ci ret = cxgb4_ethtool_flash_bootcfg(netdev, data, size); 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci default: 14068c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 14078c2ecf20Sopenharmony_ci break; 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (!ret) 14118c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 14128c2ecf20Sopenharmony_ci "loading %s successful, reload cxgb4 driver\n", 14138c2ecf20Sopenharmony_ci flash_region_strings[region]); 14148c2ecf20Sopenharmony_ci return ret; 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci#define CXGB4_FW_SIG 0x4368656c 14188c2ecf20Sopenharmony_ci#define CXGB4_FW_SIG_OFFSET 0x160 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic int cxgb4_validate_fw_image(const u8 *data, u32 *size) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci struct cxgb4_fw_data *header; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci header = (struct cxgb4_fw_data *)&data[CXGB4_FW_SIG_OFFSET]; 14258c2ecf20Sopenharmony_ci if (be32_to_cpu(header->signature) != CXGB4_FW_SIG) 14268c2ecf20Sopenharmony_ci return -EINVAL; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (size) 14298c2ecf20Sopenharmony_ci *size = be16_to_cpu(((struct fw_hdr *)data)->len512) * 512; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci return 0; 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cistatic int cxgb4_validate_bootcfg_image(const u8 *data, u32 *size) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci struct cxgb4_bootcfg_data *header; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci header = (struct cxgb4_bootcfg_data *)data; 14398c2ecf20Sopenharmony_ci if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) 14408c2ecf20Sopenharmony_ci return -EINVAL; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci return 0; 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic int cxgb4_validate_boot_image(const u8 *data, u32 *size) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci struct cxgb4_pci_exp_rom_header *exp_header; 14488c2ecf20Sopenharmony_ci struct cxgb4_pcir_data *pcir_header; 14498c2ecf20Sopenharmony_ci struct legacy_pci_rom_hdr *header; 14508c2ecf20Sopenharmony_ci const u8 *cur_header = data; 14518c2ecf20Sopenharmony_ci u16 pcir_offset; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci exp_header = (struct cxgb4_pci_exp_rom_header *)data; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if (le16_to_cpu(exp_header->signature) != BOOT_SIGNATURE) 14568c2ecf20Sopenharmony_ci return -EINVAL; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (size) { 14598c2ecf20Sopenharmony_ci do { 14608c2ecf20Sopenharmony_ci header = (struct legacy_pci_rom_hdr *)cur_header; 14618c2ecf20Sopenharmony_ci pcir_offset = le16_to_cpu(header->pcir_offset); 14628c2ecf20Sopenharmony_ci pcir_header = (struct cxgb4_pcir_data *)(cur_header + 14638c2ecf20Sopenharmony_ci pcir_offset); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci *size += header->size512 * 512; 14668c2ecf20Sopenharmony_ci cur_header += header->size512 * 512; 14678c2ecf20Sopenharmony_ci } while (!(pcir_header->indicator & CXGB4_HDR_INDI)); 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci return 0; 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci if (!cxgb4_validate_fw_image(data, size)) 14768c2ecf20Sopenharmony_ci return CXGB4_ETHTOOL_FLASH_FW; 14778c2ecf20Sopenharmony_ci if (!cxgb4_validate_boot_image(data, size)) 14788c2ecf20Sopenharmony_ci return CXGB4_ETHTOOL_FLASH_BOOT; 14798c2ecf20Sopenharmony_ci if (!cxgb4_validate_phy_image(data, size)) 14808c2ecf20Sopenharmony_ci return CXGB4_ETHTOOL_FLASH_PHY; 14818c2ecf20Sopenharmony_ci if (!cxgb4_validate_bootcfg_image(data, size)) 14828c2ecf20Sopenharmony_ci return CXGB4_ETHTOOL_FLASH_BOOTCFG; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_cistatic int set_flash(struct net_device *netdev, struct ethtool_flash *ef) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 14908c2ecf20Sopenharmony_ci const struct firmware *fw; 14918c2ecf20Sopenharmony_ci unsigned int master; 14928c2ecf20Sopenharmony_ci u8 master_vld = 0; 14938c2ecf20Sopenharmony_ci const u8 *fw_data; 14948c2ecf20Sopenharmony_ci size_t fw_size; 14958c2ecf20Sopenharmony_ci u32 size = 0; 14968c2ecf20Sopenharmony_ci u32 pcie_fw; 14978c2ecf20Sopenharmony_ci int region; 14988c2ecf20Sopenharmony_ci int ret; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci pcie_fw = t4_read_reg(adap, PCIE_FW_A); 15018c2ecf20Sopenharmony_ci master = PCIE_FW_MASTER_G(pcie_fw); 15028c2ecf20Sopenharmony_ci if (pcie_fw & PCIE_FW_MASTER_VLD_F) 15038c2ecf20Sopenharmony_ci master_vld = 1; 15048c2ecf20Sopenharmony_ci /* if csiostor is the master return */ 15058c2ecf20Sopenharmony_ci if (master_vld && (master != adap->pf)) { 15068c2ecf20Sopenharmony_ci dev_warn(adap->pdev_dev, 15078c2ecf20Sopenharmony_ci "cxgb4 driver needs to be loaded as MASTER to support FW flash\n"); 15088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci ef->data[sizeof(ef->data) - 1] = '\0'; 15128c2ecf20Sopenharmony_ci ret = request_firmware(&fw, ef->data, adap->pdev_dev); 15138c2ecf20Sopenharmony_ci if (ret < 0) 15148c2ecf20Sopenharmony_ci return ret; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci fw_data = fw->data; 15178c2ecf20Sopenharmony_ci fw_size = fw->size; 15188c2ecf20Sopenharmony_ci if (ef->region == ETHTOOL_FLASH_ALL_REGIONS) { 15198c2ecf20Sopenharmony_ci while (fw_size > 0) { 15208c2ecf20Sopenharmony_ci size = 0; 15218c2ecf20Sopenharmony_ci region = cxgb4_ethtool_get_flash_region(fw_data, &size); 15228c2ecf20Sopenharmony_ci if (region < 0 || !size) { 15238c2ecf20Sopenharmony_ci ret = region; 15248c2ecf20Sopenharmony_ci goto out_free_fw; 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci ret = cxgb4_ethtool_flash_region(netdev, fw_data, size, 15288c2ecf20Sopenharmony_ci region); 15298c2ecf20Sopenharmony_ci if (ret) 15308c2ecf20Sopenharmony_ci goto out_free_fw; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci fw_data += size; 15338c2ecf20Sopenharmony_ci fw_size -= size; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci } else { 15368c2ecf20Sopenharmony_ci ret = cxgb4_ethtool_flash_region(netdev, fw_data, fw_size, 15378c2ecf20Sopenharmony_ci ef->region); 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ciout_free_fw: 15418c2ecf20Sopenharmony_ci release_firmware(fw); 15428c2ecf20Sopenharmony_ci return ret; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic int get_ts_info(struct net_device *dev, struct ethtool_ts_info *ts_info) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 15488c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 15518c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 15528c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci ts_info->so_timestamping |= SOF_TIMESTAMPING_RX_HARDWARE | 15558c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 15568c2ecf20Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | 15598c2ecf20Sopenharmony_ci (1 << HWTSTAMP_TX_ON); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 15628c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | 15638c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | 15648c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | 15658c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | 15668c2ecf20Sopenharmony_ci (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci if (adapter->ptp_clock) 15698c2ecf20Sopenharmony_ci ts_info->phc_index = ptp_clock_index(adapter->ptp_clock); 15708c2ecf20Sopenharmony_ci else 15718c2ecf20Sopenharmony_ci ts_info->phc_index = -1; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci return 0; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic u32 get_rss_table_size(struct net_device *dev) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci return pi->rss_size; 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_cistatic int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 15868c2ecf20Sopenharmony_ci unsigned int n = pi->rss_size; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (hfunc) 15898c2ecf20Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 15908c2ecf20Sopenharmony_ci if (!p) 15918c2ecf20Sopenharmony_ci return 0; 15928c2ecf20Sopenharmony_ci while (n--) 15938c2ecf20Sopenharmony_ci p[n] = pi->rss[n]; 15948c2ecf20Sopenharmony_ci return 0; 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, 15988c2ecf20Sopenharmony_ci const u8 hfunc) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci unsigned int i; 16018c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci /* We require at least one supported parameter to be changed and no 16048c2ecf20Sopenharmony_ci * change in any of the unsupported parameters 16058c2ecf20Sopenharmony_ci */ 16068c2ecf20Sopenharmony_ci if (key || 16078c2ecf20Sopenharmony_ci (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) 16088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16098c2ecf20Sopenharmony_ci if (!p) 16108c2ecf20Sopenharmony_ci return 0; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* Interface must be brought up atleast once */ 16138c2ecf20Sopenharmony_ci if (pi->adapter->flags & CXGB4_FULL_INIT_DONE) { 16148c2ecf20Sopenharmony_ci for (i = 0; i < pi->rss_size; i++) 16158c2ecf20Sopenharmony_ci pi->rss[i] = p[i]; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci return cxgb4_write_rss(pi, pi->rss); 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci return -EPERM; 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic struct filter_entry *cxgb4_get_filter_entry(struct adapter *adap, 16248c2ecf20Sopenharmony_ci u32 ftid) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci struct tid_info *t = &adap->tids; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (ftid >= t->hpftid_base && ftid < t->hpftid_base + t->nhpftids) 16298c2ecf20Sopenharmony_ci return &t->hpftid_tab[ftid - t->hpftid_base]; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (ftid >= t->ftid_base && ftid < t->ftid_base + t->nftids) 16328c2ecf20Sopenharmony_ci return &t->ftid_tab[ftid - t->ftid_base]; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci return lookup_tid(t, ftid); 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistatic void cxgb4_fill_filter_rule(struct ethtool_rx_flow_spec *fs, 16388c2ecf20Sopenharmony_ci struct ch_filter_specification *dfs) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci switch (dfs->val.proto) { 16418c2ecf20Sopenharmony_ci case IPPROTO_TCP: 16428c2ecf20Sopenharmony_ci if (dfs->type) 16438c2ecf20Sopenharmony_ci fs->flow_type = TCP_V6_FLOW; 16448c2ecf20Sopenharmony_ci else 16458c2ecf20Sopenharmony_ci fs->flow_type = TCP_V4_FLOW; 16468c2ecf20Sopenharmony_ci break; 16478c2ecf20Sopenharmony_ci case IPPROTO_UDP: 16488c2ecf20Sopenharmony_ci if (dfs->type) 16498c2ecf20Sopenharmony_ci fs->flow_type = UDP_V6_FLOW; 16508c2ecf20Sopenharmony_ci else 16518c2ecf20Sopenharmony_ci fs->flow_type = UDP_V4_FLOW; 16528c2ecf20Sopenharmony_ci break; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (dfs->type) { 16568c2ecf20Sopenharmony_ci fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->val.fport); 16578c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->mask.fport); 16588c2ecf20Sopenharmony_ci fs->h_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->val.lport); 16598c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->mask.lport); 16608c2ecf20Sopenharmony_ci memcpy(&fs->h_u.tcp_ip6_spec.ip6src, &dfs->val.fip[0], 16618c2ecf20Sopenharmony_ci sizeof(fs->h_u.tcp_ip6_spec.ip6src)); 16628c2ecf20Sopenharmony_ci memcpy(&fs->m_u.tcp_ip6_spec.ip6src, &dfs->mask.fip[0], 16638c2ecf20Sopenharmony_ci sizeof(fs->m_u.tcp_ip6_spec.ip6src)); 16648c2ecf20Sopenharmony_ci memcpy(&fs->h_u.tcp_ip6_spec.ip6dst, &dfs->val.lip[0], 16658c2ecf20Sopenharmony_ci sizeof(fs->h_u.tcp_ip6_spec.ip6dst)); 16668c2ecf20Sopenharmony_ci memcpy(&fs->m_u.tcp_ip6_spec.ip6dst, &dfs->mask.lip[0], 16678c2ecf20Sopenharmony_ci sizeof(fs->m_u.tcp_ip6_spec.ip6dst)); 16688c2ecf20Sopenharmony_ci fs->h_u.tcp_ip6_spec.tclass = dfs->val.tos; 16698c2ecf20Sopenharmony_ci fs->m_u.tcp_ip6_spec.tclass = dfs->mask.tos; 16708c2ecf20Sopenharmony_ci } else { 16718c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->val.fport); 16728c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->mask.fport); 16738c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->val.lport); 16748c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->mask.lport); 16758c2ecf20Sopenharmony_ci memcpy(&fs->h_u.tcp_ip4_spec.ip4src, &dfs->val.fip[0], 16768c2ecf20Sopenharmony_ci sizeof(fs->h_u.tcp_ip4_spec.ip4src)); 16778c2ecf20Sopenharmony_ci memcpy(&fs->m_u.tcp_ip4_spec.ip4src, &dfs->mask.fip[0], 16788c2ecf20Sopenharmony_ci sizeof(fs->m_u.tcp_ip4_spec.ip4src)); 16798c2ecf20Sopenharmony_ci memcpy(&fs->h_u.tcp_ip4_spec.ip4dst, &dfs->val.lip[0], 16808c2ecf20Sopenharmony_ci sizeof(fs->h_u.tcp_ip4_spec.ip4dst)); 16818c2ecf20Sopenharmony_ci memcpy(&fs->m_u.tcp_ip4_spec.ip4dst, &dfs->mask.lip[0], 16828c2ecf20Sopenharmony_ci sizeof(fs->m_u.tcp_ip4_spec.ip4dst)); 16838c2ecf20Sopenharmony_ci fs->h_u.tcp_ip4_spec.tos = dfs->val.tos; 16848c2ecf20Sopenharmony_ci fs->m_u.tcp_ip4_spec.tos = dfs->mask.tos; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci fs->h_ext.vlan_tci = cpu_to_be16(dfs->val.ivlan); 16878c2ecf20Sopenharmony_ci fs->m_ext.vlan_tci = cpu_to_be16(dfs->mask.ivlan); 16888c2ecf20Sopenharmony_ci fs->flow_type |= FLOW_EXT; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (dfs->action == FILTER_DROP) 16918c2ecf20Sopenharmony_ci fs->ring_cookie = RX_CLS_FLOW_DISC; 16928c2ecf20Sopenharmony_ci else 16938c2ecf20Sopenharmony_ci fs->ring_cookie = dfs->iq; 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cistatic int cxgb4_ntuple_get_filter(struct net_device *dev, 16978c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd, 16988c2ecf20Sopenharmony_ci unsigned int loc) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 17018c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 17028c2ecf20Sopenharmony_ci struct filter_entry *f; 17038c2ecf20Sopenharmony_ci int ftid; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) 17068c2ecf20Sopenharmony_ci return -EAGAIN; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* Check for maximum filter range */ 17098c2ecf20Sopenharmony_ci if (!adap->ethtool_filters) 17108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (loc >= adap->ethtool_filters->nentries) 17138c2ecf20Sopenharmony_ci return -ERANGE; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (!test_bit(loc, adap->ethtool_filters->port[pi->port_id].bmap)) 17168c2ecf20Sopenharmony_ci return -ENOENT; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci ftid = adap->ethtool_filters->port[pi->port_id].loc_array[loc]; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Fetch filter_entry */ 17218c2ecf20Sopenharmony_ci f = cxgb4_get_filter_entry(adap, ftid); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci cxgb4_fill_filter_rule(&cmd->fs, &f->fs); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci return 0; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 17298c2ecf20Sopenharmony_ci u32 *rules) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 17328c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 17338c2ecf20Sopenharmony_ci unsigned int count = 0, index = 0; 17348c2ecf20Sopenharmony_ci int ret = 0; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci switch (info->cmd) { 17378c2ecf20Sopenharmony_ci case ETHTOOL_GRXFH: { 17388c2ecf20Sopenharmony_ci unsigned int v = pi->rss_mode; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci info->data = 0; 17418c2ecf20Sopenharmony_ci switch (info->flow_type) { 17428c2ecf20Sopenharmony_ci case TCP_V4_FLOW: 17438c2ecf20Sopenharmony_ci if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) 17448c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 17458c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 17468c2ecf20Sopenharmony_ci else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) 17478c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 17488c2ecf20Sopenharmony_ci break; 17498c2ecf20Sopenharmony_ci case UDP_V4_FLOW: 17508c2ecf20Sopenharmony_ci if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && 17518c2ecf20Sopenharmony_ci (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) 17528c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 17538c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 17548c2ecf20Sopenharmony_ci else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) 17558c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 17568c2ecf20Sopenharmony_ci break; 17578c2ecf20Sopenharmony_ci case SCTP_V4_FLOW: 17588c2ecf20Sopenharmony_ci case AH_ESP_V4_FLOW: 17598c2ecf20Sopenharmony_ci case IPV4_FLOW: 17608c2ecf20Sopenharmony_ci if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) 17618c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci case TCP_V6_FLOW: 17648c2ecf20Sopenharmony_ci if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) 17658c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 17668c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 17678c2ecf20Sopenharmony_ci else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) 17688c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 17698c2ecf20Sopenharmony_ci break; 17708c2ecf20Sopenharmony_ci case UDP_V6_FLOW: 17718c2ecf20Sopenharmony_ci if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && 17728c2ecf20Sopenharmony_ci (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) 17738c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST | 17748c2ecf20Sopenharmony_ci RXH_L4_B_0_1 | RXH_L4_B_2_3; 17758c2ecf20Sopenharmony_ci else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) 17768c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 17778c2ecf20Sopenharmony_ci break; 17788c2ecf20Sopenharmony_ci case SCTP_V6_FLOW: 17798c2ecf20Sopenharmony_ci case AH_ESP_V6_FLOW: 17808c2ecf20Sopenharmony_ci case IPV6_FLOW: 17818c2ecf20Sopenharmony_ci if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) 17828c2ecf20Sopenharmony_ci info->data = RXH_IP_SRC | RXH_IP_DST; 17838c2ecf20Sopenharmony_ci break; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci return 0; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci case ETHTOOL_GRXRINGS: 17888c2ecf20Sopenharmony_ci info->data = pi->nqsets; 17898c2ecf20Sopenharmony_ci return 0; 17908c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 17918c2ecf20Sopenharmony_ci info->rule_cnt = 17928c2ecf20Sopenharmony_ci adap->ethtool_filters->port[pi->port_id].in_use; 17938c2ecf20Sopenharmony_ci return 0; 17948c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 17958c2ecf20Sopenharmony_ci return cxgb4_ntuple_get_filter(dev, info, info->fs.location); 17968c2ecf20Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 17978c2ecf20Sopenharmony_ci info->data = adap->ethtool_filters->nentries; 17988c2ecf20Sopenharmony_ci while (count < info->rule_cnt) { 17998c2ecf20Sopenharmony_ci ret = cxgb4_ntuple_get_filter(dev, info, index); 18008c2ecf20Sopenharmony_ci if (!ret) 18018c2ecf20Sopenharmony_ci rules[count++] = index; 18028c2ecf20Sopenharmony_ci index++; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci return 0; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_cistatic int cxgb4_ntuple_del_filter(struct net_device *dev, 18118c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci struct cxgb4_ethtool_filter_info *filter_info; 18148c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 18158c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 18168c2ecf20Sopenharmony_ci struct filter_entry *f; 18178c2ecf20Sopenharmony_ci u32 filter_id; 18188c2ecf20Sopenharmony_ci int ret; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) 18218c2ecf20Sopenharmony_ci return -EAGAIN; /* can still change nfilters */ 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (!adapter->ethtool_filters) 18248c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (cmd->fs.location >= adapter->ethtool_filters->nentries) { 18278c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 18288c2ecf20Sopenharmony_ci "Location must be < %u", 18298c2ecf20Sopenharmony_ci adapter->ethtool_filters->nentries); 18308c2ecf20Sopenharmony_ci return -ERANGE; 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci filter_info = &adapter->ethtool_filters->port[pi->port_id]; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (!test_bit(cmd->fs.location, filter_info->bmap)) 18368c2ecf20Sopenharmony_ci return -ENOENT; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci filter_id = filter_info->loc_array[cmd->fs.location]; 18398c2ecf20Sopenharmony_ci f = cxgb4_get_filter_entry(adapter, filter_id); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (f->fs.prio) 18428c2ecf20Sopenharmony_ci filter_id -= adapter->tids.hpftid_base; 18438c2ecf20Sopenharmony_ci else if (!f->fs.hash) 18448c2ecf20Sopenharmony_ci filter_id -= (adapter->tids.ftid_base - adapter->tids.nhpftids); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci ret = cxgb4_flow_rule_destroy(dev, f->fs.tc_prio, &f->fs, filter_id); 18478c2ecf20Sopenharmony_ci if (ret) 18488c2ecf20Sopenharmony_ci goto err; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci clear_bit(cmd->fs.location, filter_info->bmap); 18518c2ecf20Sopenharmony_ci filter_info->in_use--; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cierr: 18548c2ecf20Sopenharmony_ci return ret; 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci/* Add Ethtool n-tuple filters. */ 18588c2ecf20Sopenharmony_cistatic int cxgb4_ntuple_set_filter(struct net_device *netdev, 18598c2ecf20Sopenharmony_ci struct ethtool_rxnfc *cmd) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci struct ethtool_rx_flow_spec_input input = {}; 18628c2ecf20Sopenharmony_ci struct cxgb4_ethtool_filter_info *filter_info; 18638c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(netdev); 18648c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 18658c2ecf20Sopenharmony_ci struct ch_filter_specification fs; 18668c2ecf20Sopenharmony_ci struct ethtool_rx_flow_rule *flow; 18678c2ecf20Sopenharmony_ci u32 tid; 18688c2ecf20Sopenharmony_ci int ret; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) 18718c2ecf20Sopenharmony_ci return -EAGAIN; /* can still change nfilters */ 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (!adapter->ethtool_filters) 18748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (cmd->fs.location >= adapter->ethtool_filters->nentries) { 18778c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 18788c2ecf20Sopenharmony_ci "Location must be < %u", 18798c2ecf20Sopenharmony_ci adapter->ethtool_filters->nentries); 18808c2ecf20Sopenharmony_ci return -ERANGE; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (test_bit(cmd->fs.location, 18848c2ecf20Sopenharmony_ci adapter->ethtool_filters->port[pi->port_id].bmap)) 18858c2ecf20Sopenharmony_ci return -EEXIST; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci memset(&fs, 0, sizeof(fs)); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci input.fs = &cmd->fs; 18908c2ecf20Sopenharmony_ci flow = ethtool_rx_flow_rule_create(&input); 18918c2ecf20Sopenharmony_ci if (IS_ERR(flow)) { 18928c2ecf20Sopenharmony_ci ret = PTR_ERR(flow); 18938c2ecf20Sopenharmony_ci goto exit; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci fs.hitcnts = 1; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci ret = cxgb4_flow_rule_replace(netdev, flow->rule, cmd->fs.location, 18998c2ecf20Sopenharmony_ci NULL, &fs, &tid); 19008c2ecf20Sopenharmony_ci if (ret) 19018c2ecf20Sopenharmony_ci goto free; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci filter_info = &adapter->ethtool_filters->port[pi->port_id]; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (fs.prio) 19068c2ecf20Sopenharmony_ci tid += adapter->tids.hpftid_base; 19078c2ecf20Sopenharmony_ci else if (!fs.hash) 19088c2ecf20Sopenharmony_ci tid += (adapter->tids.ftid_base - adapter->tids.nhpftids); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci filter_info->loc_array[cmd->fs.location] = tid; 19118c2ecf20Sopenharmony_ci set_bit(cmd->fs.location, filter_info->bmap); 19128c2ecf20Sopenharmony_ci filter_info->in_use++; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cifree: 19158c2ecf20Sopenharmony_ci ethtool_rx_flow_rule_destroy(flow); 19168c2ecf20Sopenharmony_ciexit: 19178c2ecf20Sopenharmony_ci return ret; 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_cistatic int set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci switch (cmd->cmd) { 19258c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 19268c2ecf20Sopenharmony_ci ret = cxgb4_ntuple_set_filter(dev, cmd); 19278c2ecf20Sopenharmony_ci break; 19288c2ecf20Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 19298c2ecf20Sopenharmony_ci ret = cxgb4_ntuple_del_filter(dev, cmd); 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci default: 19328c2ecf20Sopenharmony_ci break; 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci return ret; 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_cistatic int set_dump(struct net_device *dev, struct ethtool_dump *eth_dump) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 19418c2ecf20Sopenharmony_ci u32 len = 0; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci len = sizeof(struct cudbg_hdr) + 19448c2ecf20Sopenharmony_ci sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY; 19458c2ecf20Sopenharmony_ci len += cxgb4_get_dump_length(adapter, eth_dump->flag); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci adapter->eth_dump.flag = eth_dump->flag; 19488c2ecf20Sopenharmony_ci adapter->eth_dump.len = len; 19498c2ecf20Sopenharmony_ci return 0; 19508c2ecf20Sopenharmony_ci} 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_cistatic int get_dump_flag(struct net_device *dev, struct ethtool_dump *eth_dump) 19538c2ecf20Sopenharmony_ci{ 19548c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci eth_dump->flag = adapter->eth_dump.flag; 19578c2ecf20Sopenharmony_ci eth_dump->len = adapter->eth_dump.len; 19588c2ecf20Sopenharmony_ci eth_dump->version = adapter->eth_dump.version; 19598c2ecf20Sopenharmony_ci return 0; 19608c2ecf20Sopenharmony_ci} 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_cistatic int get_dump_data(struct net_device *dev, struct ethtool_dump *eth_dump, 19638c2ecf20Sopenharmony_ci void *buf) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 19668c2ecf20Sopenharmony_ci u32 len = 0; 19678c2ecf20Sopenharmony_ci int ret = 0; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (adapter->eth_dump.flag == CXGB4_ETH_DUMP_NONE) 19708c2ecf20Sopenharmony_ci return -ENOENT; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci len = sizeof(struct cudbg_hdr) + 19738c2ecf20Sopenharmony_ci sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY; 19748c2ecf20Sopenharmony_ci len += cxgb4_get_dump_length(adapter, adapter->eth_dump.flag); 19758c2ecf20Sopenharmony_ci if (eth_dump->len < len) 19768c2ecf20Sopenharmony_ci return -ENOMEM; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci ret = cxgb4_cudbg_collect(adapter, buf, &len, adapter->eth_dump.flag); 19798c2ecf20Sopenharmony_ci if (ret) 19808c2ecf20Sopenharmony_ci return ret; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci eth_dump->flag = adapter->eth_dump.flag; 19838c2ecf20Sopenharmony_ci eth_dump->len = len; 19848c2ecf20Sopenharmony_ci eth_dump->version = adapter->eth_dump.version; 19858c2ecf20Sopenharmony_ci return 0; 19868c2ecf20Sopenharmony_ci} 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_cistatic int cxgb4_get_module_info(struct net_device *dev, 19898c2ecf20Sopenharmony_ci struct ethtool_modinfo *modinfo) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 19928c2ecf20Sopenharmony_ci u8 sff8472_comp, sff_diag_type, sff_rev; 19938c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 19948c2ecf20Sopenharmony_ci int ret; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (!t4_is_inserted_mod_type(pi->mod_type)) 19978c2ecf20Sopenharmony_ci return -EINVAL; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci switch (pi->port_type) { 20008c2ecf20Sopenharmony_ci case FW_PORT_TYPE_SFP: 20018c2ecf20Sopenharmony_ci case FW_PORT_TYPE_QSA: 20028c2ecf20Sopenharmony_ci case FW_PORT_TYPE_SFP28: 20038c2ecf20Sopenharmony_ci ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 20048c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, SFF_8472_COMP_ADDR, 20058c2ecf20Sopenharmony_ci SFF_8472_COMP_LEN, &sff8472_comp); 20068c2ecf20Sopenharmony_ci if (ret) 20078c2ecf20Sopenharmony_ci return ret; 20088c2ecf20Sopenharmony_ci ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 20098c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, SFP_DIAG_TYPE_ADDR, 20108c2ecf20Sopenharmony_ci SFP_DIAG_TYPE_LEN, &sff_diag_type); 20118c2ecf20Sopenharmony_ci if (ret) 20128c2ecf20Sopenharmony_ci return ret; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci if (!sff8472_comp || (sff_diag_type & SFP_DIAG_ADDRMODE)) { 20158c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 20168c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 20178c2ecf20Sopenharmony_ci } else { 20188c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8472; 20198c2ecf20Sopenharmony_ci if (sff_diag_type & SFP_DIAG_IMPLEMENTED) 20208c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 20218c2ecf20Sopenharmony_ci else 20228c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci break; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci case FW_PORT_TYPE_QSFP: 20278c2ecf20Sopenharmony_ci case FW_PORT_TYPE_QSFP_10G: 20288c2ecf20Sopenharmony_ci case FW_PORT_TYPE_CR_QSFP: 20298c2ecf20Sopenharmony_ci case FW_PORT_TYPE_CR2_QSFP: 20308c2ecf20Sopenharmony_ci case FW_PORT_TYPE_CR4_QSFP: 20318c2ecf20Sopenharmony_ci ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 20328c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, SFF_REV_ADDR, 20338c2ecf20Sopenharmony_ci SFF_REV_LEN, &sff_rev); 20348c2ecf20Sopenharmony_ci /* For QSFP type ports, revision value >= 3 20358c2ecf20Sopenharmony_ci * means the SFP is 8636 compliant. 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ci if (ret) 20388c2ecf20Sopenharmony_ci return ret; 20398c2ecf20Sopenharmony_ci if (sff_rev >= 0x3) { 20408c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8636; 20418c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 20428c2ecf20Sopenharmony_ci } else { 20438c2ecf20Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 20448c2ecf20Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci break; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci default: 20498c2ecf20Sopenharmony_ci return -EINVAL; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci return 0; 20538c2ecf20Sopenharmony_ci} 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_cistatic int cxgb4_get_module_eeprom(struct net_device *dev, 20568c2ecf20Sopenharmony_ci struct ethtool_eeprom *eprom, u8 *data) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci int ret = 0, offset = eprom->offset, len = eprom->len; 20598c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 20608c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci memset(data, 0, eprom->len); 20638c2ecf20Sopenharmony_ci if (offset + len <= I2C_PAGE_SIZE) 20648c2ecf20Sopenharmony_ci return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 20658c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, offset, len, data); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci /* offset + len spans 0xa0 and 0xa1 pages */ 20688c2ecf20Sopenharmony_ci if (offset <= I2C_PAGE_SIZE) { 20698c2ecf20Sopenharmony_ci /* read 0xa0 page */ 20708c2ecf20Sopenharmony_ci len = I2C_PAGE_SIZE - offset; 20718c2ecf20Sopenharmony_ci ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 20728c2ecf20Sopenharmony_ci I2C_DEV_ADDR_A0, offset, len, data); 20738c2ecf20Sopenharmony_ci if (ret) 20748c2ecf20Sopenharmony_ci return ret; 20758c2ecf20Sopenharmony_ci offset = I2C_PAGE_SIZE; 20768c2ecf20Sopenharmony_ci /* Remaining bytes to be read from second page = 20778c2ecf20Sopenharmony_ci * Total length - bytes read from first page 20788c2ecf20Sopenharmony_ci */ 20798c2ecf20Sopenharmony_ci len = eprom->len - len; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci /* Read additional optical diagnostics from page 0xa2 if supported */ 20828c2ecf20Sopenharmony_ci return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, I2C_DEV_ADDR_A2, 20838c2ecf20Sopenharmony_ci offset, len, &data[eprom->len - len]); 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_cistatic u32 cxgb4_get_priv_flags(struct net_device *netdev) 20878c2ecf20Sopenharmony_ci{ 20888c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 20898c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci return (adapter->eth_flags | pi->eth_flags); 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci/** 20958c2ecf20Sopenharmony_ci * set_flags - set/unset specified flags if passed in new_flags 20968c2ecf20Sopenharmony_ci * @cur_flags: pointer to current flags 20978c2ecf20Sopenharmony_ci * @new_flags: new incoming flags 20988c2ecf20Sopenharmony_ci * @flags: set of flags to set/unset 20998c2ecf20Sopenharmony_ci */ 21008c2ecf20Sopenharmony_cistatic inline void set_flags(u32 *cur_flags, u32 new_flags, u32 flags) 21018c2ecf20Sopenharmony_ci{ 21028c2ecf20Sopenharmony_ci *cur_flags = (*cur_flags & ~flags) | (new_flags & flags); 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_cistatic int cxgb4_set_priv_flags(struct net_device *netdev, u32 flags) 21068c2ecf20Sopenharmony_ci{ 21078c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 21088c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci set_flags(&adapter->eth_flags, flags, PRIV_FLAGS_ADAP); 21118c2ecf20Sopenharmony_ci set_flags(&pi->eth_flags, flags, PRIV_FLAGS_PORT); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci return 0; 21148c2ecf20Sopenharmony_ci} 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_cistatic void cxgb4_lb_test(struct net_device *netdev, u64 *lb_status) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci int dev_state = netif_running(netdev); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (dev_state) { 21218c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(netdev); 21228c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci *lb_status = cxgb4_selftest_lb_pkt(netdev); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci if (dev_state) { 21288c2ecf20Sopenharmony_ci netif_tx_start_all_queues(netdev); 21298c2ecf20Sopenharmony_ci netif_carrier_on(netdev); 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci} 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_cistatic void cxgb4_self_test(struct net_device *netdev, 21348c2ecf20Sopenharmony_ci struct ethtool_test *eth_test, u64 *data) 21358c2ecf20Sopenharmony_ci{ 21368c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 21378c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci memset(data, 0, sizeof(u64) * CXGB4_ETHTOOL_MAX_TEST); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE) || 21428c2ecf20Sopenharmony_ci !(adap->flags & CXGB4_FW_OK)) { 21438c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 21448c2ecf20Sopenharmony_ci return; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci if (eth_test->flags & ETH_TEST_FL_OFFLINE) 21488c2ecf20Sopenharmony_ci cxgb4_lb_test(netdev, &data[CXGB4_ETHTOOL_LB_TEST]); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci if (data[CXGB4_ETHTOOL_LB_TEST]) 21518c2ecf20Sopenharmony_ci eth_test->flags |= ETH_TEST_FL_FAILED; 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic const struct ethtool_ops cxgb_ethtool_ops = { 21558c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 21568c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_RX_MAX_FRAMES | 21578c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_TX_USECS_IRQ | 21588c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 21598c2ecf20Sopenharmony_ci .get_link_ksettings = get_link_ksettings, 21608c2ecf20Sopenharmony_ci .set_link_ksettings = set_link_ksettings, 21618c2ecf20Sopenharmony_ci .get_fecparam = get_fecparam, 21628c2ecf20Sopenharmony_ci .set_fecparam = set_fecparam, 21638c2ecf20Sopenharmony_ci .get_drvinfo = get_drvinfo, 21648c2ecf20Sopenharmony_ci .get_msglevel = get_msglevel, 21658c2ecf20Sopenharmony_ci .set_msglevel = set_msglevel, 21668c2ecf20Sopenharmony_ci .get_ringparam = get_sge_param, 21678c2ecf20Sopenharmony_ci .set_ringparam = set_sge_param, 21688c2ecf20Sopenharmony_ci .get_coalesce = get_coalesce, 21698c2ecf20Sopenharmony_ci .set_coalesce = set_coalesce, 21708c2ecf20Sopenharmony_ci .get_eeprom_len = get_eeprom_len, 21718c2ecf20Sopenharmony_ci .get_eeprom = get_eeprom, 21728c2ecf20Sopenharmony_ci .set_eeprom = set_eeprom, 21738c2ecf20Sopenharmony_ci .get_pauseparam = get_pauseparam, 21748c2ecf20Sopenharmony_ci .set_pauseparam = set_pauseparam, 21758c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 21768c2ecf20Sopenharmony_ci .get_strings = get_strings, 21778c2ecf20Sopenharmony_ci .set_phys_id = identify_port, 21788c2ecf20Sopenharmony_ci .nway_reset = restart_autoneg, 21798c2ecf20Sopenharmony_ci .get_sset_count = get_sset_count, 21808c2ecf20Sopenharmony_ci .get_ethtool_stats = get_stats, 21818c2ecf20Sopenharmony_ci .get_regs_len = get_regs_len, 21828c2ecf20Sopenharmony_ci .get_regs = get_regs, 21838c2ecf20Sopenharmony_ci .get_rxnfc = get_rxnfc, 21848c2ecf20Sopenharmony_ci .set_rxnfc = set_rxnfc, 21858c2ecf20Sopenharmony_ci .get_rxfh_indir_size = get_rss_table_size, 21868c2ecf20Sopenharmony_ci .get_rxfh = get_rss_table, 21878c2ecf20Sopenharmony_ci .set_rxfh = set_rss_table, 21888c2ecf20Sopenharmony_ci .self_test = cxgb4_self_test, 21898c2ecf20Sopenharmony_ci .flash_device = set_flash, 21908c2ecf20Sopenharmony_ci .get_ts_info = get_ts_info, 21918c2ecf20Sopenharmony_ci .set_dump = set_dump, 21928c2ecf20Sopenharmony_ci .get_dump_flag = get_dump_flag, 21938c2ecf20Sopenharmony_ci .get_dump_data = get_dump_data, 21948c2ecf20Sopenharmony_ci .get_module_info = cxgb4_get_module_info, 21958c2ecf20Sopenharmony_ci .get_module_eeprom = cxgb4_get_module_eeprom, 21968c2ecf20Sopenharmony_ci .get_priv_flags = cxgb4_get_priv_flags, 21978c2ecf20Sopenharmony_ci .set_priv_flags = cxgb4_set_priv_flags, 21988c2ecf20Sopenharmony_ci}; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_civoid cxgb4_cleanup_ethtool_filters(struct adapter *adap) 22018c2ecf20Sopenharmony_ci{ 22028c2ecf20Sopenharmony_ci struct cxgb4_ethtool_filter_info *eth_filter_info; 22038c2ecf20Sopenharmony_ci u8 i; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci if (!adap->ethtool_filters) 22068c2ecf20Sopenharmony_ci return; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci eth_filter_info = adap->ethtool_filters->port; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci if (eth_filter_info) { 22118c2ecf20Sopenharmony_ci for (i = 0; i < adap->params.nports; i++) { 22128c2ecf20Sopenharmony_ci kvfree(eth_filter_info[i].loc_array); 22138c2ecf20Sopenharmony_ci kfree(eth_filter_info[i].bmap); 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci kfree(eth_filter_info); 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci kfree(adap->ethtool_filters); 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ciint cxgb4_init_ethtool_filters(struct adapter *adap) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct cxgb4_ethtool_filter_info *eth_filter_info; 22248c2ecf20Sopenharmony_ci struct cxgb4_ethtool_filter *eth_filter; 22258c2ecf20Sopenharmony_ci struct tid_info *tids = &adap->tids; 22268c2ecf20Sopenharmony_ci u32 nentries, i; 22278c2ecf20Sopenharmony_ci int ret; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci eth_filter = kzalloc(sizeof(*eth_filter), GFP_KERNEL); 22308c2ecf20Sopenharmony_ci if (!eth_filter) 22318c2ecf20Sopenharmony_ci return -ENOMEM; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci eth_filter_info = kcalloc(adap->params.nports, 22348c2ecf20Sopenharmony_ci sizeof(*eth_filter_info), 22358c2ecf20Sopenharmony_ci GFP_KERNEL); 22368c2ecf20Sopenharmony_ci if (!eth_filter_info) { 22378c2ecf20Sopenharmony_ci ret = -ENOMEM; 22388c2ecf20Sopenharmony_ci goto free_eth_filter; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci eth_filter->port = eth_filter_info; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci nentries = tids->nhpftids + tids->nftids; 22448c2ecf20Sopenharmony_ci if (is_hashfilter(adap)) 22458c2ecf20Sopenharmony_ci nentries += tids->nhash + 22468c2ecf20Sopenharmony_ci (adap->tids.stid_base - adap->tids.tid_base); 22478c2ecf20Sopenharmony_ci eth_filter->nentries = nentries; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci for (i = 0; i < adap->params.nports; i++) { 22508c2ecf20Sopenharmony_ci eth_filter->port[i].loc_array = kvzalloc(nentries, GFP_KERNEL); 22518c2ecf20Sopenharmony_ci if (!eth_filter->port[i].loc_array) { 22528c2ecf20Sopenharmony_ci ret = -ENOMEM; 22538c2ecf20Sopenharmony_ci goto free_eth_finfo; 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci eth_filter->port[i].bmap = kcalloc(BITS_TO_LONGS(nentries), 22578c2ecf20Sopenharmony_ci sizeof(unsigned long), 22588c2ecf20Sopenharmony_ci GFP_KERNEL); 22598c2ecf20Sopenharmony_ci if (!eth_filter->port[i].bmap) { 22608c2ecf20Sopenharmony_ci ret = -ENOMEM; 22618c2ecf20Sopenharmony_ci goto free_eth_finfo; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci } 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci adap->ethtool_filters = eth_filter; 22668c2ecf20Sopenharmony_ci return 0; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_cifree_eth_finfo: 22698c2ecf20Sopenharmony_ci while (i-- > 0) { 22708c2ecf20Sopenharmony_ci kfree(eth_filter->port[i].bmap); 22718c2ecf20Sopenharmony_ci kvfree(eth_filter->port[i].loc_array); 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci kfree(eth_filter_info); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_cifree_eth_filter: 22768c2ecf20Sopenharmony_ci kfree(eth_filter); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci return ret; 22798c2ecf20Sopenharmony_ci} 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_civoid cxgb4_set_ethtool_ops(struct net_device *netdev) 22828c2ecf20Sopenharmony_ci{ 22838c2ecf20Sopenharmony_ci netdev->ethtool_ops = &cxgb_ethtool_ops; 22848c2ecf20Sopenharmony_ci} 2285