14fa9c49fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2812034f1SHariprasad Shenai /* 3812034f1SHariprasad Shenai * Copyright (C) 2013-2015 Chelsio Communications. All rights reserved. 4812034f1SHariprasad Shenai */ 5812034f1SHariprasad Shenai 6812034f1SHariprasad Shenai #include <linux/firmware.h> 7812034f1SHariprasad Shenai #include <linux/mdio.h> 8812034f1SHariprasad Shenai 9812034f1SHariprasad Shenai #include "cxgb4.h" 10812034f1SHariprasad Shenai #include "t4_regs.h" 11812034f1SHariprasad Shenai #include "t4fw_api.h" 12ad75b7d3SRahul Lakkireddy #include "cxgb4_cudbg.h" 13d915c299SVishal Kulkarni #include "cxgb4_filter.h" 14c8729cacSVishal Kulkarni #include "cxgb4_tc_flower.h" 15812034f1SHariprasad Shenai 16812034f1SHariprasad Shenai #define EEPROM_MAGIC 0x38E2F10C 17812034f1SHariprasad Shenai 18812034f1SHariprasad Shenai static u32 get_msglevel(struct net_device *dev) 19812034f1SHariprasad Shenai { 20812034f1SHariprasad Shenai return netdev2adap(dev)->msg_enable; 21812034f1SHariprasad Shenai } 22812034f1SHariprasad Shenai 23812034f1SHariprasad Shenai static void set_msglevel(struct net_device *dev, u32 val) 24812034f1SHariprasad Shenai { 25812034f1SHariprasad Shenai netdev2adap(dev)->msg_enable = val; 26812034f1SHariprasad Shenai } 27812034f1SHariprasad Shenai 287235ffaeSVishal Kulkarni enum cxgb4_ethtool_tests { 297235ffaeSVishal Kulkarni CXGB4_ETHTOOL_LB_TEST, 307235ffaeSVishal Kulkarni CXGB4_ETHTOOL_MAX_TEST, 317235ffaeSVishal Kulkarni }; 327235ffaeSVishal Kulkarni 337235ffaeSVishal Kulkarni static const char cxgb4_selftest_strings[CXGB4_ETHTOOL_MAX_TEST][ETH_GSTRING_LEN] = { 34fd4ec076SRahul Lakkireddy "Loop back test (offline)", 357235ffaeSVishal Kulkarni }; 367235ffaeSVishal Kulkarni 373893c905SVishal Kulkarni static const char * const flash_region_strings[] = { 383893c905SVishal Kulkarni "All", 393893c905SVishal Kulkarni "Firmware", 404ee339e1SVishal Kulkarni "PHY Firmware", 4155088355SVishal Kulkarni "Boot", 42d5002c9aSVishal Kulkarni "Boot CFG", 433893c905SVishal Kulkarni }; 443893c905SVishal Kulkarni 45812034f1SHariprasad Shenai static const char stats_strings[][ETH_GSTRING_LEN] = { 46eed7342dSHariprasad Shenai "tx_octets_ok ", 47eed7342dSHariprasad Shenai "tx_frames_ok ", 48eed7342dSHariprasad Shenai "tx_broadcast_frames ", 49eed7342dSHariprasad Shenai "tx_multicast_frames ", 50eed7342dSHariprasad Shenai "tx_unicast_frames ", 51eed7342dSHariprasad Shenai "tx_error_frames ", 52812034f1SHariprasad Shenai 53eed7342dSHariprasad Shenai "tx_frames_64 ", 54eed7342dSHariprasad Shenai "tx_frames_65_to_127 ", 55eed7342dSHariprasad Shenai "tx_frames_128_to_255 ", 56eed7342dSHariprasad Shenai "tx_frames_256_to_511 ", 57eed7342dSHariprasad Shenai "tx_frames_512_to_1023 ", 58eed7342dSHariprasad Shenai "tx_frames_1024_to_1518 ", 59eed7342dSHariprasad Shenai "tx_frames_1519_to_max ", 60812034f1SHariprasad Shenai 61eed7342dSHariprasad Shenai "tx_frames_dropped ", 62eed7342dSHariprasad Shenai "tx_pause_frames ", 63eed7342dSHariprasad Shenai "tx_ppp0_frames ", 64eed7342dSHariprasad Shenai "tx_ppp1_frames ", 65eed7342dSHariprasad Shenai "tx_ppp2_frames ", 66eed7342dSHariprasad Shenai "tx_ppp3_frames ", 67eed7342dSHariprasad Shenai "tx_ppp4_frames ", 68eed7342dSHariprasad Shenai "tx_ppp5_frames ", 69eed7342dSHariprasad Shenai "tx_ppp6_frames ", 70eed7342dSHariprasad Shenai "tx_ppp7_frames ", 71812034f1SHariprasad Shenai 72eed7342dSHariprasad Shenai "rx_octets_ok ", 73eed7342dSHariprasad Shenai "rx_frames_ok ", 74eed7342dSHariprasad Shenai "rx_broadcast_frames ", 75eed7342dSHariprasad Shenai "rx_multicast_frames ", 76eed7342dSHariprasad Shenai "rx_unicast_frames ", 77812034f1SHariprasad Shenai 78eed7342dSHariprasad Shenai "rx_frames_too_long ", 79eed7342dSHariprasad Shenai "rx_jabber_errors ", 80eed7342dSHariprasad Shenai "rx_fcs_errors ", 81eed7342dSHariprasad Shenai "rx_length_errors ", 82eed7342dSHariprasad Shenai "rx_symbol_errors ", 83eed7342dSHariprasad Shenai "rx_runt_frames ", 84812034f1SHariprasad Shenai 85eed7342dSHariprasad Shenai "rx_frames_64 ", 86eed7342dSHariprasad Shenai "rx_frames_65_to_127 ", 87eed7342dSHariprasad Shenai "rx_frames_128_to_255 ", 88eed7342dSHariprasad Shenai "rx_frames_256_to_511 ", 89eed7342dSHariprasad Shenai "rx_frames_512_to_1023 ", 90eed7342dSHariprasad Shenai "rx_frames_1024_to_1518 ", 91eed7342dSHariprasad Shenai "rx_frames_1519_to_max ", 92812034f1SHariprasad Shenai 93eed7342dSHariprasad Shenai "rx_pause_frames ", 94eed7342dSHariprasad Shenai "rx_ppp0_frames ", 95eed7342dSHariprasad Shenai "rx_ppp1_frames ", 96eed7342dSHariprasad Shenai "rx_ppp2_frames ", 97eed7342dSHariprasad Shenai "rx_ppp3_frames ", 98eed7342dSHariprasad Shenai "rx_ppp4_frames ", 99eed7342dSHariprasad Shenai "rx_ppp5_frames ", 100eed7342dSHariprasad Shenai "rx_ppp6_frames ", 101eed7342dSHariprasad Shenai "rx_ppp7_frames ", 102812034f1SHariprasad Shenai 103eed7342dSHariprasad Shenai "rx_bg0_frames_dropped ", 104eed7342dSHariprasad Shenai "rx_bg1_frames_dropped ", 105eed7342dSHariprasad Shenai "rx_bg2_frames_dropped ", 106eed7342dSHariprasad Shenai "rx_bg3_frames_dropped ", 107eed7342dSHariprasad Shenai "rx_bg0_frames_trunc ", 108eed7342dSHariprasad Shenai "rx_bg1_frames_trunc ", 109eed7342dSHariprasad Shenai "rx_bg2_frames_trunc ", 110eed7342dSHariprasad Shenai "rx_bg3_frames_trunc ", 111812034f1SHariprasad Shenai 112eed7342dSHariprasad Shenai "tso ", 1131a2a14fbSRahul Lakkireddy "uso ", 114eed7342dSHariprasad Shenai "tx_csum_offload ", 115eed7342dSHariprasad Shenai "rx_csum_good ", 116eed7342dSHariprasad Shenai "vlan_extractions ", 117eed7342dSHariprasad Shenai "vlan_insertions ", 118eed7342dSHariprasad Shenai "gro_packets ", 119eed7342dSHariprasad Shenai "gro_merged ", 120a8c16e8eSRohit Maheshwari #if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 121a0190431SRohit Maheshwari "tx_tls_encrypted_packets", 122a0190431SRohit Maheshwari "tx_tls_encrypted_bytes ", 123a0190431SRohit Maheshwari "tx_tls_ctx ", 124a0190431SRohit Maheshwari "tx_tls_ooo ", 125a0190431SRohit Maheshwari "tx_tls_skip_no_sync_data", 126a0190431SRohit Maheshwari "tx_tls_drop_no_sync_data", 127a0190431SRohit Maheshwari "tx_tls_drop_bypass_req ", 128a0190431SRohit Maheshwari #endif 129812034f1SHariprasad Shenai }; 130812034f1SHariprasad Shenai 1313427e13eSRohit Maheshwari static char adapter_stats_strings[][ETH_GSTRING_LEN] = { 1323427e13eSRohit Maheshwari "db_drop ", 1333427e13eSRohit Maheshwari "db_full ", 1343427e13eSRohit Maheshwari "db_empty ", 1353427e13eSRohit Maheshwari "write_coal_success ", 1363427e13eSRohit Maheshwari "write_coal_fail ", 1373427e13eSRohit Maheshwari }; 1383427e13eSRohit Maheshwari 13965046e84SHariprasad Shenai static char loopback_stats_strings[][ETH_GSTRING_LEN] = { 14065046e84SHariprasad Shenai "-------Loopback----------- ", 14165046e84SHariprasad Shenai "octets_ok ", 14265046e84SHariprasad Shenai "frames_ok ", 14365046e84SHariprasad Shenai "bcast_frames ", 14465046e84SHariprasad Shenai "mcast_frames ", 14565046e84SHariprasad Shenai "ucast_frames ", 14665046e84SHariprasad Shenai "error_frames ", 14765046e84SHariprasad Shenai "frames_64 ", 14865046e84SHariprasad Shenai "frames_65_to_127 ", 14965046e84SHariprasad Shenai "frames_128_to_255 ", 15065046e84SHariprasad Shenai "frames_256_to_511 ", 15165046e84SHariprasad Shenai "frames_512_to_1023 ", 15265046e84SHariprasad Shenai "frames_1024_to_1518 ", 15365046e84SHariprasad Shenai "frames_1519_to_max ", 15465046e84SHariprasad Shenai "frames_dropped ", 15565046e84SHariprasad Shenai "bg0_frames_dropped ", 15665046e84SHariprasad Shenai "bg1_frames_dropped ", 15765046e84SHariprasad Shenai "bg2_frames_dropped ", 15865046e84SHariprasad Shenai "bg3_frames_dropped ", 15965046e84SHariprasad Shenai "bg0_frames_trunc ", 16065046e84SHariprasad Shenai "bg1_frames_trunc ", 16165046e84SHariprasad Shenai "bg2_frames_trunc ", 16265046e84SHariprasad Shenai "bg3_frames_trunc ", 16365046e84SHariprasad Shenai }; 16465046e84SHariprasad Shenai 165c90d1604SArjun Vynipadath static const char cxgb4_priv_flags_strings[][ETH_GSTRING_LEN] = { 166c90d1604SArjun Vynipadath [PRIV_FLAG_PORT_TX_VM_BIT] = "port_tx_vm_wr", 167c90d1604SArjun Vynipadath }; 168c90d1604SArjun Vynipadath 169812034f1SHariprasad Shenai static int get_sset_count(struct net_device *dev, int sset) 170812034f1SHariprasad Shenai { 171812034f1SHariprasad Shenai switch (sset) { 172812034f1SHariprasad Shenai case ETH_SS_STATS: 173a4cfd929SHariprasad Shenai return ARRAY_SIZE(stats_strings) + 174a6222975SHariprasad Shenai ARRAY_SIZE(adapter_stats_strings) + 17565046e84SHariprasad Shenai ARRAY_SIZE(loopback_stats_strings); 176c90d1604SArjun Vynipadath case ETH_SS_PRIV_FLAGS: 177c90d1604SArjun Vynipadath return ARRAY_SIZE(cxgb4_priv_flags_strings); 1787235ffaeSVishal Kulkarni case ETH_SS_TEST: 1797235ffaeSVishal Kulkarni return ARRAY_SIZE(cxgb4_selftest_strings); 180812034f1SHariprasad Shenai default: 181812034f1SHariprasad Shenai return -EOPNOTSUPP; 182812034f1SHariprasad Shenai } 183812034f1SHariprasad Shenai } 184812034f1SHariprasad Shenai 185812034f1SHariprasad Shenai static int get_regs_len(struct net_device *dev) 186812034f1SHariprasad Shenai { 187812034f1SHariprasad Shenai struct adapter *adap = netdev2adap(dev); 188812034f1SHariprasad Shenai 189812034f1SHariprasad Shenai return t4_get_regs_len(adap); 190812034f1SHariprasad Shenai } 191812034f1SHariprasad Shenai 192812034f1SHariprasad Shenai static int get_eeprom_len(struct net_device *dev) 193812034f1SHariprasad Shenai { 194812034f1SHariprasad Shenai return EEPROMSIZE; 195812034f1SHariprasad Shenai } 196812034f1SHariprasad Shenai 197812034f1SHariprasad Shenai static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 198812034f1SHariprasad Shenai { 199812034f1SHariprasad Shenai struct adapter *adapter = netdev2adap(dev); 200812034f1SHariprasad Shenai u32 exprom_vers; 201812034f1SHariprasad Shenai 202812034f1SHariprasad Shenai strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); 203812034f1SHariprasad Shenai strlcpy(info->bus_info, pci_name(adapter->pdev), 204812034f1SHariprasad Shenai sizeof(info->bus_info)); 205b08f2b35SHariprasad Shenai info->regdump_len = get_regs_len(dev); 206812034f1SHariprasad Shenai 20750ad85c2SLeon Romanovsky if (adapter->params.fw_vers) 208812034f1SHariprasad Shenai snprintf(info->fw_version, sizeof(info->fw_version), 209812034f1SHariprasad Shenai "%u.%u.%u.%u, TP %u.%u.%u.%u", 210812034f1SHariprasad Shenai FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), 211812034f1SHariprasad Shenai FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), 212812034f1SHariprasad Shenai FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), 213812034f1SHariprasad Shenai FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), 214812034f1SHariprasad Shenai FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), 215812034f1SHariprasad Shenai FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), 216812034f1SHariprasad Shenai FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), 217812034f1SHariprasad Shenai FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); 218812034f1SHariprasad Shenai 219812034f1SHariprasad Shenai if (!t4_get_exprom_version(adapter, &exprom_vers)) 220812034f1SHariprasad Shenai snprintf(info->erom_version, sizeof(info->erom_version), 221812034f1SHariprasad Shenai "%u.%u.%u.%u", 222812034f1SHariprasad Shenai FW_HDR_FW_VER_MAJOR_G(exprom_vers), 223812034f1SHariprasad Shenai FW_HDR_FW_VER_MINOR_G(exprom_vers), 224812034f1SHariprasad Shenai FW_HDR_FW_VER_MICRO_G(exprom_vers), 225812034f1SHariprasad Shenai FW_HDR_FW_VER_BUILD_G(exprom_vers)); 226c90d1604SArjun Vynipadath info->n_priv_flags = ARRAY_SIZE(cxgb4_priv_flags_strings); 227812034f1SHariprasad Shenai } 228812034f1SHariprasad Shenai 229812034f1SHariprasad Shenai static void get_strings(struct net_device *dev, u32 stringset, u8 *data) 230812034f1SHariprasad Shenai { 231a4cfd929SHariprasad Shenai if (stringset == ETH_SS_STATS) { 232812034f1SHariprasad Shenai memcpy(data, stats_strings, sizeof(stats_strings)); 233a4cfd929SHariprasad Shenai data += sizeof(stats_strings); 234a4cfd929SHariprasad Shenai memcpy(data, adapter_stats_strings, 235a4cfd929SHariprasad Shenai sizeof(adapter_stats_strings)); 236a6222975SHariprasad Shenai data += sizeof(adapter_stats_strings); 23765046e84SHariprasad Shenai memcpy(data, loopback_stats_strings, 23865046e84SHariprasad Shenai sizeof(loopback_stats_strings)); 239c90d1604SArjun Vynipadath } else if (stringset == ETH_SS_PRIV_FLAGS) { 240c90d1604SArjun Vynipadath memcpy(data, cxgb4_priv_flags_strings, 241c90d1604SArjun Vynipadath sizeof(cxgb4_priv_flags_strings)); 2427235ffaeSVishal Kulkarni } else if (stringset == ETH_SS_TEST) { 2437235ffaeSVishal Kulkarni memcpy(data, cxgb4_selftest_strings, 2447235ffaeSVishal Kulkarni sizeof(cxgb4_selftest_strings)); 245a4cfd929SHariprasad Shenai } 246812034f1SHariprasad Shenai } 247812034f1SHariprasad Shenai 248812034f1SHariprasad Shenai /* port stats maintained per queue of the port. They should be in the same 249812034f1SHariprasad Shenai * order as in stats_strings above. 250812034f1SHariprasad Shenai */ 251812034f1SHariprasad Shenai struct queue_port_stats { 252812034f1SHariprasad Shenai u64 tso; 2531a2a14fbSRahul Lakkireddy u64 uso; 254812034f1SHariprasad Shenai u64 tx_csum; 255812034f1SHariprasad Shenai u64 rx_csum; 256812034f1SHariprasad Shenai u64 vlan_ex; 257812034f1SHariprasad Shenai u64 vlan_ins; 258812034f1SHariprasad Shenai u64 gro_pkts; 259812034f1SHariprasad Shenai u64 gro_merged; 260a8c16e8eSRohit Maheshwari #if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 261a0190431SRohit Maheshwari u64 tx_tls_encrypted_packets; 262a0190431SRohit Maheshwari u64 tx_tls_encrypted_bytes; 263a0190431SRohit Maheshwari u64 tx_tls_ctx; 264a0190431SRohit Maheshwari u64 tx_tls_ooo; 265a0190431SRohit Maheshwari u64 tx_tls_skip_no_sync_data; 266a0190431SRohit Maheshwari u64 tx_tls_drop_no_sync_data; 267a0190431SRohit Maheshwari u64 tx_tls_drop_bypass_req; 268a0190431SRohit Maheshwari #endif 269a4cfd929SHariprasad Shenai }; 270a4cfd929SHariprasad Shenai 2713427e13eSRohit Maheshwari struct adapter_stats { 2723427e13eSRohit Maheshwari u64 db_drop; 2733427e13eSRohit Maheshwari u64 db_full; 2743427e13eSRohit Maheshwari u64 db_empty; 2753427e13eSRohit Maheshwari u64 wc_success; 2763427e13eSRohit Maheshwari u64 wc_fail; 2773427e13eSRohit Maheshwari }; 2783427e13eSRohit Maheshwari 279812034f1SHariprasad Shenai static void collect_sge_port_stats(const struct adapter *adap, 280812034f1SHariprasad Shenai const struct port_info *p, 281812034f1SHariprasad Shenai struct queue_port_stats *s) 282812034f1SHariprasad Shenai { 283812034f1SHariprasad Shenai const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; 284812034f1SHariprasad Shenai const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; 2853427e13eSRohit Maheshwari #if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 2863427e13eSRohit Maheshwari const struct ch_ktls_port_stats_debug *ktls_stats; 2873427e13eSRohit Maheshwari #endif 2888311f0beSRahul Lakkireddy struct sge_eohw_txq *eohw_tx; 2898311f0beSRahul Lakkireddy unsigned int i; 290812034f1SHariprasad Shenai 291812034f1SHariprasad Shenai memset(s, 0, sizeof(*s)); 292812034f1SHariprasad Shenai for (i = 0; i < p->nqsets; i++, rx++, tx++) { 293812034f1SHariprasad Shenai s->tso += tx->tso; 2941a2a14fbSRahul Lakkireddy s->uso += tx->uso; 295812034f1SHariprasad Shenai s->tx_csum += tx->tx_cso; 296812034f1SHariprasad Shenai s->rx_csum += rx->stats.rx_cso; 297812034f1SHariprasad Shenai s->vlan_ex += rx->stats.vlan_ex; 298812034f1SHariprasad Shenai s->vlan_ins += tx->vlan_ins; 299812034f1SHariprasad Shenai s->gro_pkts += rx->stats.lro_pkts; 300812034f1SHariprasad Shenai s->gro_merged += rx->stats.lro_merged; 301812034f1SHariprasad Shenai } 3028311f0beSRahul Lakkireddy 3038311f0beSRahul Lakkireddy if (adap->sge.eohw_txq) { 3048311f0beSRahul Lakkireddy eohw_tx = &adap->sge.eohw_txq[p->first_qset]; 3058311f0beSRahul Lakkireddy for (i = 0; i < p->nqsets; i++, eohw_tx++) { 3068311f0beSRahul Lakkireddy s->tso += eohw_tx->tso; 3078311f0beSRahul Lakkireddy s->uso += eohw_tx->uso; 3088311f0beSRahul Lakkireddy s->tx_csum += eohw_tx->tx_cso; 3098311f0beSRahul Lakkireddy s->vlan_ins += eohw_tx->vlan_ins; 3108311f0beSRahul Lakkireddy } 3118311f0beSRahul Lakkireddy } 3123427e13eSRohit Maheshwari #if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 3133427e13eSRohit Maheshwari ktls_stats = &adap->ch_ktls_stats.ktls_port[p->port_id]; 3143427e13eSRohit Maheshwari s->tx_tls_encrypted_packets = 3153427e13eSRohit Maheshwari atomic64_read(&ktls_stats->ktls_tx_encrypted_packets); 3163427e13eSRohit Maheshwari s->tx_tls_encrypted_bytes = 3173427e13eSRohit Maheshwari atomic64_read(&ktls_stats->ktls_tx_encrypted_bytes); 3183427e13eSRohit Maheshwari s->tx_tls_ctx = atomic64_read(&ktls_stats->ktls_tx_ctx); 3193427e13eSRohit Maheshwari s->tx_tls_ooo = atomic64_read(&ktls_stats->ktls_tx_ooo); 3203427e13eSRohit Maheshwari s->tx_tls_skip_no_sync_data = 3213427e13eSRohit Maheshwari atomic64_read(&ktls_stats->ktls_tx_skip_no_sync_data); 3223427e13eSRohit Maheshwari s->tx_tls_drop_no_sync_data = 3233427e13eSRohit Maheshwari atomic64_read(&ktls_stats->ktls_tx_drop_no_sync_data); 3243427e13eSRohit Maheshwari s->tx_tls_drop_bypass_req = 3253427e13eSRohit Maheshwari atomic64_read(&ktls_stats->ktls_tx_drop_bypass_req); 3263427e13eSRohit Maheshwari #endif 327812034f1SHariprasad Shenai } 328812034f1SHariprasad Shenai 329a4cfd929SHariprasad Shenai static void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s) 330a4cfd929SHariprasad Shenai { 331a4cfd929SHariprasad Shenai u64 val1, val2; 332a4cfd929SHariprasad Shenai 333a4cfd929SHariprasad Shenai memset(s, 0, sizeof(*s)); 334a4cfd929SHariprasad Shenai 335a4cfd929SHariprasad Shenai s->db_drop = adap->db_stats.db_drop; 336a4cfd929SHariprasad Shenai s->db_full = adap->db_stats.db_full; 337a4cfd929SHariprasad Shenai s->db_empty = adap->db_stats.db_empty; 338a4cfd929SHariprasad Shenai 339a4cfd929SHariprasad Shenai if (!is_t4(adap->params.chip)) { 340a4cfd929SHariprasad Shenai int v; 341a4cfd929SHariprasad Shenai 342a4cfd929SHariprasad Shenai v = t4_read_reg(adap, SGE_STAT_CFG_A); 343a4cfd929SHariprasad Shenai if (STATSOURCE_T5_G(v) == 7) { 344a4cfd929SHariprasad Shenai val2 = t4_read_reg(adap, SGE_STAT_MATCH_A); 345a4cfd929SHariprasad Shenai val1 = t4_read_reg(adap, SGE_STAT_TOTAL_A); 346a4cfd929SHariprasad Shenai s->wc_success = val1 - val2; 347a4cfd929SHariprasad Shenai s->wc_fail = val2; 348a4cfd929SHariprasad Shenai } 349a4cfd929SHariprasad Shenai } 350a4cfd929SHariprasad Shenai } 351a4cfd929SHariprasad Shenai 352812034f1SHariprasad Shenai static void get_stats(struct net_device *dev, struct ethtool_stats *stats, 353812034f1SHariprasad Shenai u64 *data) 354812034f1SHariprasad Shenai { 355812034f1SHariprasad Shenai struct port_info *pi = netdev_priv(dev); 356812034f1SHariprasad Shenai struct adapter *adapter = pi->adapter; 35765046e84SHariprasad Shenai struct lb_port_stats s; 35865046e84SHariprasad Shenai int i; 35965046e84SHariprasad Shenai u64 *p0; 360812034f1SHariprasad Shenai 361a4cfd929SHariprasad Shenai t4_get_port_stats_offset(adapter, pi->tx_chan, 362a4cfd929SHariprasad Shenai (struct port_stats *)data, 363a4cfd929SHariprasad Shenai &pi->stats_base); 364812034f1SHariprasad Shenai 365812034f1SHariprasad Shenai data += sizeof(struct port_stats) / sizeof(u64); 366812034f1SHariprasad Shenai collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); 367812034f1SHariprasad Shenai data += sizeof(struct queue_port_stats) / sizeof(u64); 368a4cfd929SHariprasad Shenai collect_adapter_stats(adapter, (struct adapter_stats *)data); 369a6222975SHariprasad Shenai data += sizeof(struct adapter_stats) / sizeof(u64); 370a6222975SHariprasad Shenai 371a6222975SHariprasad Shenai *data++ = (u64)pi->port_id; 37265046e84SHariprasad Shenai memset(&s, 0, sizeof(s)); 37365046e84SHariprasad Shenai t4_get_lb_stats(adapter, pi->port_id, &s); 37465046e84SHariprasad Shenai 37565046e84SHariprasad Shenai p0 = &s.octets; 37665046e84SHariprasad Shenai for (i = 0; i < ARRAY_SIZE(loopback_stats_strings) - 1; i++) 37765046e84SHariprasad Shenai *data++ = (unsigned long long)*p0++; 378812034f1SHariprasad Shenai } 379812034f1SHariprasad Shenai 380812034f1SHariprasad Shenai static void get_regs(struct net_device *dev, struct ethtool_regs *regs, 381812034f1SHariprasad Shenai void *buf) 382812034f1SHariprasad Shenai { 383812034f1SHariprasad Shenai struct adapter *adap = netdev2adap(dev); 384812034f1SHariprasad Shenai size_t buf_size; 385812034f1SHariprasad Shenai 386812034f1SHariprasad Shenai buf_size = t4_get_regs_len(adap); 387812034f1SHariprasad Shenai regs->version = mk_adap_vers(adap); 388812034f1SHariprasad Shenai t4_get_regs(adap, buf, buf_size); 389812034f1SHariprasad Shenai } 390812034f1SHariprasad Shenai 391812034f1SHariprasad Shenai static int restart_autoneg(struct net_device *dev) 392812034f1SHariprasad Shenai { 393812034f1SHariprasad Shenai struct port_info *p = netdev_priv(dev); 394812034f1SHariprasad Shenai 395812034f1SHariprasad Shenai if (!netif_running(dev)) 396812034f1SHariprasad Shenai return -EAGAIN; 397812034f1SHariprasad Shenai if (p->link_cfg.autoneg != AUTONEG_ENABLE) 398812034f1SHariprasad Shenai return -EINVAL; 399b2612722SHariprasad Shenai t4_restart_aneg(p->adapter, p->adapter->pf, p->tx_chan); 400812034f1SHariprasad Shenai return 0; 401812034f1SHariprasad Shenai } 402812034f1SHariprasad Shenai 403812034f1SHariprasad Shenai static int identify_port(struct net_device *dev, 404812034f1SHariprasad Shenai enum ethtool_phys_id_state state) 405812034f1SHariprasad Shenai { 406812034f1SHariprasad Shenai unsigned int val; 407812034f1SHariprasad Shenai struct adapter *adap = netdev2adap(dev); 408812034f1SHariprasad Shenai 409812034f1SHariprasad Shenai if (state == ETHTOOL_ID_ACTIVE) 410812034f1SHariprasad Shenai val = 0xffff; 411812034f1SHariprasad Shenai else if (state == ETHTOOL_ID_INACTIVE) 412812034f1SHariprasad Shenai val = 0; 413812034f1SHariprasad Shenai else 414812034f1SHariprasad Shenai return -EINVAL; 415812034f1SHariprasad Shenai 416b2612722SHariprasad Shenai return t4_identify_port(adap, adap->pf, netdev2pinfo(dev)->viid, val); 417812034f1SHariprasad Shenai } 418812034f1SHariprasad Shenai 419eb97ad99SGanesh Goudar /** 420eb97ad99SGanesh Goudar * from_fw_port_mod_type - translate Firmware Port/Module type to Ethtool 421eb97ad99SGanesh Goudar * @port_type: Firmware Port Type 422eb97ad99SGanesh Goudar * @mod_type: Firmware Module Type 423eb97ad99SGanesh Goudar * 424eb97ad99SGanesh Goudar * Translate Firmware Port/Module type to Ethtool Port Type. 425eb97ad99SGanesh Goudar */ 426eb97ad99SGanesh Goudar static int from_fw_port_mod_type(enum fw_port_type port_type, 427eb97ad99SGanesh Goudar enum fw_port_module_type mod_type) 428812034f1SHariprasad Shenai { 429eb97ad99SGanesh Goudar if (port_type == FW_PORT_TYPE_BT_SGMII || 430eb97ad99SGanesh Goudar port_type == FW_PORT_TYPE_BT_XFI || 431eb97ad99SGanesh Goudar port_type == FW_PORT_TYPE_BT_XAUI) { 432eb97ad99SGanesh Goudar return PORT_TP; 433eb97ad99SGanesh Goudar } else if (port_type == FW_PORT_TYPE_FIBER_XFI || 434eb97ad99SGanesh Goudar port_type == FW_PORT_TYPE_FIBER_XAUI) { 435eb97ad99SGanesh Goudar return PORT_FIBRE; 436eb97ad99SGanesh Goudar } else if (port_type == FW_PORT_TYPE_SFP || 437eb97ad99SGanesh Goudar port_type == FW_PORT_TYPE_QSFP_10G || 438eb97ad99SGanesh Goudar port_type == FW_PORT_TYPE_QSA || 4392061ec3fSGanesh Goudar port_type == FW_PORT_TYPE_QSFP || 4402061ec3fSGanesh Goudar port_type == FW_PORT_TYPE_CR4_QSFP || 4412061ec3fSGanesh Goudar port_type == FW_PORT_TYPE_CR_QSFP || 4422061ec3fSGanesh Goudar port_type == FW_PORT_TYPE_CR2_QSFP || 4432061ec3fSGanesh Goudar port_type == FW_PORT_TYPE_SFP28) { 444eb97ad99SGanesh Goudar if (mod_type == FW_PORT_MOD_TYPE_LR || 445eb97ad99SGanesh Goudar mod_type == FW_PORT_MOD_TYPE_SR || 446eb97ad99SGanesh Goudar mod_type == FW_PORT_MOD_TYPE_ER || 447eb97ad99SGanesh Goudar mod_type == FW_PORT_MOD_TYPE_LRM) 448eb97ad99SGanesh Goudar return PORT_FIBRE; 449eb97ad99SGanesh Goudar else if (mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || 450eb97ad99SGanesh Goudar mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) 451eb97ad99SGanesh Goudar return PORT_DA; 452812034f1SHariprasad Shenai else 453eb97ad99SGanesh Goudar return PORT_OTHER; 4542061ec3fSGanesh Goudar } else if (port_type == FW_PORT_TYPE_KR4_100G || 455b39ab140SGanesh Goudar port_type == FW_PORT_TYPE_KR_SFP28 || 456b39ab140SGanesh Goudar port_type == FW_PORT_TYPE_KR_XLAUI) { 4572061ec3fSGanesh Goudar return PORT_NONE; 458812034f1SHariprasad Shenai } 459812034f1SHariprasad Shenai 460eb97ad99SGanesh Goudar return PORT_OTHER; 461812034f1SHariprasad Shenai } 462812034f1SHariprasad Shenai 463eb97ad99SGanesh Goudar /** 464eb97ad99SGanesh Goudar * speed_to_fw_caps - translate Port Speed to Firmware Port Capabilities 465eb97ad99SGanesh Goudar * @speed: speed in Kb/s 466eb97ad99SGanesh Goudar * 467eb97ad99SGanesh Goudar * Translates a specific Port Speed into a Firmware Port Capabilities 468eb97ad99SGanesh Goudar * value. 469eb97ad99SGanesh Goudar */ 470eb97ad99SGanesh Goudar static unsigned int speed_to_fw_caps(int speed) 471812034f1SHariprasad Shenai { 472812034f1SHariprasad Shenai if (speed == 100) 473c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_100M; 474812034f1SHariprasad Shenai if (speed == 1000) 475c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_1G; 476812034f1SHariprasad Shenai if (speed == 10000) 477c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_10G; 478eb97ad99SGanesh Goudar if (speed == 25000) 479c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_25G; 480812034f1SHariprasad Shenai if (speed == 40000) 481c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_40G; 482c3168cabSGanesh Goudar if (speed == 50000) 483c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_50G; 484eb97ad99SGanesh Goudar if (speed == 100000) 485c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_100G; 486c3168cabSGanesh Goudar if (speed == 200000) 487c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_200G; 488c3168cabSGanesh Goudar if (speed == 400000) 489c3168cabSGanesh Goudar return FW_PORT_CAP32_SPEED_400G; 490812034f1SHariprasad Shenai return 0; 491812034f1SHariprasad Shenai } 492812034f1SHariprasad Shenai 493eb97ad99SGanesh Goudar /** 494eb97ad99SGanesh Goudar * fw_caps_to_lmm - translate Firmware to ethtool Link Mode Mask 495eb97ad99SGanesh Goudar * @port_type: Firmware Port Type 496eb97ad99SGanesh Goudar * @fw_caps: Firmware Port Capabilities 497eb97ad99SGanesh Goudar * @link_mode_mask: ethtool Link Mode Mask 498eb97ad99SGanesh Goudar * 499eb97ad99SGanesh Goudar * Translate a Firmware Port Capabilities specification to an ethtool 500eb97ad99SGanesh Goudar * Link Mode Mask. 501eb97ad99SGanesh Goudar */ 502eb97ad99SGanesh Goudar static void fw_caps_to_lmm(enum fw_port_type port_type, 5039f764898SVishal Kulkarni fw_port_cap32_t fw_caps, 504eb97ad99SGanesh Goudar unsigned long *link_mode_mask) 505812034f1SHariprasad Shenai { 506c3168cabSGanesh Goudar #define SET_LMM(__lmm_name) \ 50795eb7882SVishal Kulkarni do { \ 508c3168cabSGanesh Goudar __set_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ 50995eb7882SVishal Kulkarni link_mode_mask); \ 51095eb7882SVishal Kulkarni } while (0) 511812034f1SHariprasad Shenai 512eb97ad99SGanesh Goudar #define FW_CAPS_TO_LMM(__fw_name, __lmm_name) \ 513eb97ad99SGanesh Goudar do { \ 514c3168cabSGanesh Goudar if (fw_caps & FW_PORT_CAP32_ ## __fw_name) \ 515eb97ad99SGanesh Goudar SET_LMM(__lmm_name); \ 516eb97ad99SGanesh Goudar } while (0) 517eb97ad99SGanesh Goudar 518eb97ad99SGanesh Goudar switch (port_type) { 519eb97ad99SGanesh Goudar case FW_PORT_TYPE_BT_SGMII: 520eb97ad99SGanesh Goudar case FW_PORT_TYPE_BT_XFI: 521eb97ad99SGanesh Goudar case FW_PORT_TYPE_BT_XAUI: 522eb97ad99SGanesh Goudar SET_LMM(TP); 523eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_100M, 100baseT_Full); 524eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 525eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 526eb97ad99SGanesh Goudar break; 527eb97ad99SGanesh Goudar 528eb97ad99SGanesh Goudar case FW_PORT_TYPE_KX4: 529eb97ad99SGanesh Goudar case FW_PORT_TYPE_KX: 530eb97ad99SGanesh Goudar SET_LMM(Backplane); 531eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 532eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKX4_Full); 533eb97ad99SGanesh Goudar break; 534eb97ad99SGanesh Goudar 535eb97ad99SGanesh Goudar case FW_PORT_TYPE_KR: 536eb97ad99SGanesh Goudar SET_LMM(Backplane); 537129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 538eb97ad99SGanesh Goudar break; 539eb97ad99SGanesh Goudar 540eb97ad99SGanesh Goudar case FW_PORT_TYPE_BP_AP: 541eb97ad99SGanesh Goudar SET_LMM(Backplane); 542129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 543129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseR_FEC); 544129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 545eb97ad99SGanesh Goudar break; 546eb97ad99SGanesh Goudar 547eb97ad99SGanesh Goudar case FW_PORT_TYPE_BP4_AP: 548eb97ad99SGanesh Goudar SET_LMM(Backplane); 549129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 550129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseR_FEC); 551129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 552129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKX4_Full); 553eb97ad99SGanesh Goudar break; 554eb97ad99SGanesh Goudar 555eb97ad99SGanesh Goudar case FW_PORT_TYPE_FIBER_XFI: 556eb97ad99SGanesh Goudar case FW_PORT_TYPE_FIBER_XAUI: 557eb97ad99SGanesh Goudar case FW_PORT_TYPE_SFP: 558eb97ad99SGanesh Goudar case FW_PORT_TYPE_QSFP_10G: 559eb97ad99SGanesh Goudar case FW_PORT_TYPE_QSA: 560eb97ad99SGanesh Goudar SET_LMM(FIBRE); 561eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 562eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 563eb97ad99SGanesh Goudar break; 564eb97ad99SGanesh Goudar 565eb97ad99SGanesh Goudar case FW_PORT_TYPE_BP40_BA: 566eb97ad99SGanesh Goudar case FW_PORT_TYPE_QSFP: 567eb97ad99SGanesh Goudar SET_LMM(FIBRE); 568129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 569129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 570129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full); 571eb97ad99SGanesh Goudar break; 572eb97ad99SGanesh Goudar 573eb97ad99SGanesh Goudar case FW_PORT_TYPE_CR_QSFP: 574eb97ad99SGanesh Goudar case FW_PORT_TYPE_SFP28: 575eb97ad99SGanesh Goudar SET_LMM(FIBRE); 5762061ec3fSGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5772061ec3fSGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full); 5782061ec3fSGanesh Goudar FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); 5792061ec3fSGanesh Goudar break; 5802061ec3fSGanesh Goudar 5812061ec3fSGanesh Goudar case FW_PORT_TYPE_KR_SFP28: 5822061ec3fSGanesh Goudar SET_LMM(Backplane); 5832061ec3fSGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 5842061ec3fSGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 5852061ec3fSGanesh Goudar FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full); 5862061ec3fSGanesh Goudar break; 5872061ec3fSGanesh Goudar 588b39ab140SGanesh Goudar case FW_PORT_TYPE_KR_XLAUI: 589b39ab140SGanesh Goudar SET_LMM(Backplane); 590b39ab140SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseKX_Full); 591b39ab140SGanesh Goudar FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 592b39ab140SGanesh Goudar FW_CAPS_TO_LMM(SPEED_40G, 40000baseKR4_Full); 593b39ab140SGanesh Goudar break; 594b39ab140SGanesh Goudar 5952061ec3fSGanesh Goudar case FW_PORT_TYPE_CR2_QSFP: 5962061ec3fSGanesh Goudar SET_LMM(FIBRE); 597129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_50G, 50000baseSR2_Full); 598eb97ad99SGanesh Goudar break; 599eb97ad99SGanesh Goudar 600eb97ad99SGanesh Goudar case FW_PORT_TYPE_KR4_100G: 601eb97ad99SGanesh Goudar case FW_PORT_TYPE_CR4_QSFP: 602eb97ad99SGanesh Goudar SET_LMM(FIBRE); 603129cf5f7SGanesh Goudar FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full); 60495eb7882SVishal Kulkarni FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full); 605c3168cabSGanesh Goudar FW_CAPS_TO_LMM(SPEED_40G, 40000baseSR4_Full); 606c3168cabSGanesh Goudar FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full); 607c3168cabSGanesh Goudar FW_CAPS_TO_LMM(SPEED_50G, 50000baseCR2_Full); 608c3168cabSGanesh Goudar FW_CAPS_TO_LMM(SPEED_100G, 100000baseCR4_Full); 609eb97ad99SGanesh Goudar break; 610eb97ad99SGanesh Goudar 611eb97ad99SGanesh Goudar default: 612eb97ad99SGanesh Goudar break; 613eb97ad99SGanesh Goudar } 614eb97ad99SGanesh Goudar 61595eb7882SVishal Kulkarni if (fw_caps & FW_PORT_CAP32_FEC_V(FW_PORT_CAP32_FEC_M)) { 61695eb7882SVishal Kulkarni FW_CAPS_TO_LMM(FEC_RS, FEC_RS); 61795eb7882SVishal Kulkarni FW_CAPS_TO_LMM(FEC_BASER_RS, FEC_BASER); 61895eb7882SVishal Kulkarni } else { 61995eb7882SVishal Kulkarni SET_LMM(FEC_NONE); 62095eb7882SVishal Kulkarni } 62195eb7882SVishal Kulkarni 622eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(ANEG, Autoneg); 623eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(802_3_PAUSE, Pause); 624eb97ad99SGanesh Goudar FW_CAPS_TO_LMM(802_3_ASM_DIR, Asym_Pause); 625eb97ad99SGanesh Goudar 626eb97ad99SGanesh Goudar #undef FW_CAPS_TO_LMM 627eb97ad99SGanesh Goudar #undef SET_LMM 628eb97ad99SGanesh Goudar } 629eb97ad99SGanesh Goudar 630eb97ad99SGanesh Goudar /** 631eb97ad99SGanesh Goudar * lmm_to_fw_caps - translate ethtool Link Mode Mask to Firmware 632eb97ad99SGanesh Goudar * capabilities 63329bbf5d7SRahul Lakkireddy * @link_mode_mask: ethtool Link Mode Mask 634eb97ad99SGanesh Goudar * 635eb97ad99SGanesh Goudar * Translate ethtool Link Mode Mask into a Firmware Port capabilities 636eb97ad99SGanesh Goudar * value. 637eb97ad99SGanesh Goudar */ 638eb97ad99SGanesh Goudar static unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask) 639eb97ad99SGanesh Goudar { 640eb97ad99SGanesh Goudar unsigned int fw_caps = 0; 641eb97ad99SGanesh Goudar 642eb97ad99SGanesh Goudar #define LMM_TO_FW_CAPS(__lmm_name, __fw_name) \ 643eb97ad99SGanesh Goudar do { \ 644eb97ad99SGanesh Goudar if (test_bit(ETHTOOL_LINK_MODE_ ## __lmm_name ## _BIT, \ 645eb97ad99SGanesh Goudar link_mode_mask)) \ 646c3168cabSGanesh Goudar fw_caps |= FW_PORT_CAP32_ ## __fw_name; \ 647eb97ad99SGanesh Goudar } while (0) 648eb97ad99SGanesh Goudar 649eb97ad99SGanesh Goudar LMM_TO_FW_CAPS(100baseT_Full, SPEED_100M); 650eb97ad99SGanesh Goudar LMM_TO_FW_CAPS(1000baseT_Full, SPEED_1G); 651eb97ad99SGanesh Goudar LMM_TO_FW_CAPS(10000baseT_Full, SPEED_10G); 652eb97ad99SGanesh Goudar LMM_TO_FW_CAPS(40000baseSR4_Full, SPEED_40G); 653eb97ad99SGanesh Goudar LMM_TO_FW_CAPS(25000baseCR_Full, SPEED_25G); 654c3168cabSGanesh Goudar LMM_TO_FW_CAPS(50000baseCR2_Full, SPEED_50G); 655eb97ad99SGanesh Goudar LMM_TO_FW_CAPS(100000baseCR4_Full, SPEED_100G); 656eb97ad99SGanesh Goudar 657eb97ad99SGanesh Goudar #undef LMM_TO_FW_CAPS 658eb97ad99SGanesh Goudar 659eb97ad99SGanesh Goudar return fw_caps; 660eb97ad99SGanesh Goudar } 661eb97ad99SGanesh Goudar 662eb97ad99SGanesh Goudar static int get_link_ksettings(struct net_device *dev, 663eb97ad99SGanesh Goudar struct ethtool_link_ksettings *link_ksettings) 664eb97ad99SGanesh Goudar { 6652061ec3fSGanesh Goudar struct port_info *pi = netdev_priv(dev); 666eb97ad99SGanesh Goudar struct ethtool_link_settings *base = &link_ksettings->base; 667eb97ad99SGanesh Goudar 6682061ec3fSGanesh Goudar /* For the nonce, the Firmware doesn't send up Port State changes 6692061ec3fSGanesh Goudar * when the Virtual Interface attached to the Port is down. So 6702061ec3fSGanesh Goudar * if it's down, let's grab any changes. 6712061ec3fSGanesh Goudar */ 6722061ec3fSGanesh Goudar if (!netif_running(dev)) 6732061ec3fSGanesh Goudar (void)t4_update_port_info(pi); 6742061ec3fSGanesh Goudar 675c3168cabSGanesh Goudar ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 676c3168cabSGanesh Goudar ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 677c3168cabSGanesh Goudar ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising); 678c3168cabSGanesh Goudar 679eb97ad99SGanesh Goudar base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type); 680eb97ad99SGanesh Goudar 681eb97ad99SGanesh Goudar if (pi->mdio_addr >= 0) { 682eb97ad99SGanesh Goudar base->phy_address = pi->mdio_addr; 683eb97ad99SGanesh Goudar base->mdio_support = (pi->port_type == FW_PORT_TYPE_BT_SGMII 684eb97ad99SGanesh Goudar ? ETH_MDIO_SUPPORTS_C22 685eb97ad99SGanesh Goudar : ETH_MDIO_SUPPORTS_C45); 686eb97ad99SGanesh Goudar } else { 687eb97ad99SGanesh Goudar base->phy_address = 255; 688eb97ad99SGanesh Goudar base->mdio_support = 0; 689eb97ad99SGanesh Goudar } 690eb97ad99SGanesh Goudar 691c3168cabSGanesh Goudar fw_caps_to_lmm(pi->port_type, pi->link_cfg.pcaps, 692eb97ad99SGanesh Goudar link_ksettings->link_modes.supported); 6939f764898SVishal Kulkarni fw_caps_to_lmm(pi->port_type, 6949f764898SVishal Kulkarni t4_link_acaps(pi->adapter, 6959f764898SVishal Kulkarni pi->lport, 6969f764898SVishal Kulkarni &pi->link_cfg), 697eb97ad99SGanesh Goudar link_ksettings->link_modes.advertising); 698c3168cabSGanesh Goudar fw_caps_to_lmm(pi->port_type, pi->link_cfg.lpacaps, 699eb97ad99SGanesh Goudar link_ksettings->link_modes.lp_advertising); 700eb97ad99SGanesh Goudar 701bc1b5030SGanesh Goudar base->speed = (netif_carrier_ok(dev) 702bc1b5030SGanesh Goudar ? pi->link_cfg.speed 703bc1b5030SGanesh Goudar : SPEED_UNKNOWN); 704eb97ad99SGanesh Goudar base->duplex = DUPLEX_FULL; 705eb97ad99SGanesh Goudar 706eb97ad99SGanesh Goudar base->autoneg = pi->link_cfg.autoneg; 707c3168cabSGanesh Goudar if (pi->link_cfg.pcaps & FW_PORT_CAP32_ANEG) 708eb97ad99SGanesh Goudar ethtool_link_ksettings_add_link_mode(link_ksettings, 709eb97ad99SGanesh Goudar supported, Autoneg); 710eb97ad99SGanesh Goudar if (pi->link_cfg.autoneg) 711eb97ad99SGanesh Goudar ethtool_link_ksettings_add_link_mode(link_ksettings, 712eb97ad99SGanesh Goudar advertising, Autoneg); 713eb97ad99SGanesh Goudar 714eb97ad99SGanesh Goudar return 0; 715eb97ad99SGanesh Goudar } 716eb97ad99SGanesh Goudar 717eb97ad99SGanesh Goudar static int set_link_ksettings(struct net_device *dev, 718c3168cabSGanesh Goudar const struct ethtool_link_ksettings *link_ksettings) 719eb97ad99SGanesh Goudar { 720eb97ad99SGanesh Goudar struct port_info *pi = netdev_priv(dev); 721eb97ad99SGanesh Goudar struct link_config *lc = &pi->link_cfg; 722eb97ad99SGanesh Goudar const struct ethtool_link_settings *base = &link_ksettings->base; 723eb97ad99SGanesh Goudar struct link_config old_lc; 724eb97ad99SGanesh Goudar unsigned int fw_caps; 725eb97ad99SGanesh Goudar int ret = 0; 726eb97ad99SGanesh Goudar 727eb97ad99SGanesh Goudar /* only full-duplex supported */ 728eb97ad99SGanesh Goudar if (base->duplex != DUPLEX_FULL) 729812034f1SHariprasad Shenai return -EINVAL; 730812034f1SHariprasad Shenai 73141165428SHariprasad Shenai old_lc = *lc; 73257ccaedbSGanesh Goudar if (!(lc->pcaps & FW_PORT_CAP32_ANEG) || 73357ccaedbSGanesh Goudar base->autoneg == AUTONEG_DISABLE) { 734eb97ad99SGanesh Goudar fw_caps = speed_to_fw_caps(base->speed); 735812034f1SHariprasad Shenai 73695eb7882SVishal Kulkarni /* Speed must be supported by Physical Port Capabilities. */ 73795eb7882SVishal Kulkarni if (!(lc->pcaps & fw_caps)) 738812034f1SHariprasad Shenai return -EINVAL; 73957ccaedbSGanesh Goudar 740c3168cabSGanesh Goudar lc->speed_caps = fw_caps; 74157ccaedbSGanesh Goudar lc->acaps = fw_caps; 742812034f1SHariprasad Shenai } else { 743eb97ad99SGanesh Goudar fw_caps = 744eb97ad99SGanesh Goudar lmm_to_fw_caps(link_ksettings->link_modes.advertising); 745c3168cabSGanesh Goudar if (!(lc->pcaps & fw_caps)) 746812034f1SHariprasad Shenai return -EINVAL; 747c3168cabSGanesh Goudar lc->speed_caps = 0; 748c3168cabSGanesh Goudar lc->acaps = fw_caps | FW_PORT_CAP32_ANEG; 749812034f1SHariprasad Shenai } 750eb97ad99SGanesh Goudar lc->autoneg = base->autoneg; 751812034f1SHariprasad Shenai 75241165428SHariprasad Shenai /* If the firmware rejects the Link Configuration request, back out 75341165428SHariprasad Shenai * the changes and report the error. 75441165428SHariprasad Shenai */ 755eb97ad99SGanesh Goudar ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox, pi->tx_chan, lc); 75641165428SHariprasad Shenai if (ret) 75741165428SHariprasad Shenai *lc = old_lc; 75841165428SHariprasad Shenai 75941165428SHariprasad Shenai return ret; 760812034f1SHariprasad Shenai } 761812034f1SHariprasad Shenai 7627fece840SCasey Leedom /* Translate the Firmware FEC value into the ethtool value. */ 7637fece840SCasey Leedom static inline unsigned int fwcap_to_eth_fec(unsigned int fw_fec) 7647fece840SCasey Leedom { 7657fece840SCasey Leedom unsigned int eth_fec = 0; 7667fece840SCasey Leedom 767c3168cabSGanesh Goudar if (fw_fec & FW_PORT_CAP32_FEC_RS) 7687fece840SCasey Leedom eth_fec |= ETHTOOL_FEC_RS; 769c3168cabSGanesh Goudar if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS) 7707fece840SCasey Leedom eth_fec |= ETHTOOL_FEC_BASER; 7717fece840SCasey Leedom 7727fece840SCasey Leedom /* if nothing is set, then FEC is off */ 7737fece840SCasey Leedom if (!eth_fec) 7747fece840SCasey Leedom eth_fec = ETHTOOL_FEC_OFF; 7757fece840SCasey Leedom 7767fece840SCasey Leedom return eth_fec; 7777fece840SCasey Leedom } 7787fece840SCasey Leedom 7797fece840SCasey Leedom /* Translate Common Code FEC value into ethtool value. */ 7807fece840SCasey Leedom static inline unsigned int cc_to_eth_fec(unsigned int cc_fec) 7817fece840SCasey Leedom { 7827fece840SCasey Leedom unsigned int eth_fec = 0; 7837fece840SCasey Leedom 7847fece840SCasey Leedom if (cc_fec & FEC_AUTO) 7857fece840SCasey Leedom eth_fec |= ETHTOOL_FEC_AUTO; 7867fece840SCasey Leedom if (cc_fec & FEC_RS) 7877fece840SCasey Leedom eth_fec |= ETHTOOL_FEC_RS; 7887fece840SCasey Leedom if (cc_fec & FEC_BASER_RS) 7897fece840SCasey Leedom eth_fec |= ETHTOOL_FEC_BASER; 7907fece840SCasey Leedom 7917fece840SCasey Leedom /* if nothing is set, then FEC is off */ 7927fece840SCasey Leedom if (!eth_fec) 7937fece840SCasey Leedom eth_fec = ETHTOOL_FEC_OFF; 7947fece840SCasey Leedom 7957fece840SCasey Leedom return eth_fec; 7967fece840SCasey Leedom } 7977fece840SCasey Leedom 7987fece840SCasey Leedom /* Translate ethtool FEC value into Common Code value. */ 7997fece840SCasey Leedom static inline unsigned int eth_to_cc_fec(unsigned int eth_fec) 8007fece840SCasey Leedom { 8017fece840SCasey Leedom unsigned int cc_fec = 0; 8027fece840SCasey Leedom 8037fece840SCasey Leedom if (eth_fec & ETHTOOL_FEC_OFF) 8047fece840SCasey Leedom return cc_fec; 8057fece840SCasey Leedom 8067fece840SCasey Leedom if (eth_fec & ETHTOOL_FEC_AUTO) 8077fece840SCasey Leedom cc_fec |= FEC_AUTO; 8087fece840SCasey Leedom if (eth_fec & ETHTOOL_FEC_RS) 8097fece840SCasey Leedom cc_fec |= FEC_RS; 8107fece840SCasey Leedom if (eth_fec & ETHTOOL_FEC_BASER) 8117fece840SCasey Leedom cc_fec |= FEC_BASER_RS; 8127fece840SCasey Leedom 8137fece840SCasey Leedom return cc_fec; 8147fece840SCasey Leedom } 8157fece840SCasey Leedom 8167fece840SCasey Leedom static int get_fecparam(struct net_device *dev, struct ethtool_fecparam *fec) 8177fece840SCasey Leedom { 8187fece840SCasey Leedom const struct port_info *pi = netdev_priv(dev); 8197fece840SCasey Leedom const struct link_config *lc = &pi->link_cfg; 8207fece840SCasey Leedom 8217fece840SCasey Leedom /* Translate the Firmware FEC Support into the ethtool value. We 8227fece840SCasey Leedom * always support IEEE 802.3 "automatic" selection of Link FEC type if 8237fece840SCasey Leedom * any FEC is supported. 8247fece840SCasey Leedom */ 825c3168cabSGanesh Goudar fec->fec = fwcap_to_eth_fec(lc->pcaps); 8267fece840SCasey Leedom if (fec->fec != ETHTOOL_FEC_OFF) 8277fece840SCasey Leedom fec->fec |= ETHTOOL_FEC_AUTO; 8287fece840SCasey Leedom 8297fece840SCasey Leedom /* Translate the current internal FEC parameters into the 8307fece840SCasey Leedom * ethtool values. 8317fece840SCasey Leedom */ 8327fece840SCasey Leedom fec->active_fec = cc_to_eth_fec(lc->fec); 8337fece840SCasey Leedom 8347fece840SCasey Leedom return 0; 8357fece840SCasey Leedom } 8367fece840SCasey Leedom 8377fece840SCasey Leedom static int set_fecparam(struct net_device *dev, struct ethtool_fecparam *fec) 8387fece840SCasey Leedom { 8397fece840SCasey Leedom struct port_info *pi = netdev_priv(dev); 8407fece840SCasey Leedom struct link_config *lc = &pi->link_cfg; 8417fece840SCasey Leedom struct link_config old_lc; 8427fece840SCasey Leedom int ret; 8437fece840SCasey Leedom 8447fece840SCasey Leedom /* Save old Link Configuration in case the L1 Configure below 8457fece840SCasey Leedom * fails. 8467fece840SCasey Leedom */ 8477fece840SCasey Leedom old_lc = *lc; 8487fece840SCasey Leedom 8497fece840SCasey Leedom /* Try to perform the L1 Configure and return the result of that 8507fece840SCasey Leedom * effort. If it fails, revert the attempted change. 8517fece840SCasey Leedom */ 8527fece840SCasey Leedom lc->requested_fec = eth_to_cc_fec(fec->fec); 8537fece840SCasey Leedom ret = t4_link_l1cfg(pi->adapter, pi->adapter->mbox, 8547fece840SCasey Leedom pi->tx_chan, lc); 8557fece840SCasey Leedom if (ret) 8567fece840SCasey Leedom *lc = old_lc; 8577fece840SCasey Leedom return ret; 8587fece840SCasey Leedom } 8597fece840SCasey Leedom 860812034f1SHariprasad Shenai static void get_pauseparam(struct net_device *dev, 861812034f1SHariprasad Shenai struct ethtool_pauseparam *epause) 862812034f1SHariprasad Shenai { 863812034f1SHariprasad Shenai struct port_info *p = netdev_priv(dev); 864812034f1SHariprasad Shenai 865812034f1SHariprasad Shenai epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; 8660caeaf6aSRahul Lakkireddy epause->rx_pause = (p->link_cfg.advertised_fc & PAUSE_RX) != 0; 8670caeaf6aSRahul Lakkireddy epause->tx_pause = (p->link_cfg.advertised_fc & PAUSE_TX) != 0; 868812034f1SHariprasad Shenai } 869812034f1SHariprasad Shenai 870812034f1SHariprasad Shenai static int set_pauseparam(struct net_device *dev, 871812034f1SHariprasad Shenai struct ethtool_pauseparam *epause) 872812034f1SHariprasad Shenai { 873812034f1SHariprasad Shenai struct port_info *p = netdev_priv(dev); 874812034f1SHariprasad Shenai struct link_config *lc = &p->link_cfg; 875812034f1SHariprasad Shenai 876812034f1SHariprasad Shenai if (epause->autoneg == AUTONEG_DISABLE) 877812034f1SHariprasad Shenai lc->requested_fc = 0; 878c3168cabSGanesh Goudar else if (lc->pcaps & FW_PORT_CAP32_ANEG) 879812034f1SHariprasad Shenai lc->requested_fc = PAUSE_AUTONEG; 880812034f1SHariprasad Shenai else 881812034f1SHariprasad Shenai return -EINVAL; 882812034f1SHariprasad Shenai 883812034f1SHariprasad Shenai if (epause->rx_pause) 884812034f1SHariprasad Shenai lc->requested_fc |= PAUSE_RX; 885812034f1SHariprasad Shenai if (epause->tx_pause) 886812034f1SHariprasad Shenai lc->requested_fc |= PAUSE_TX; 887812034f1SHariprasad Shenai if (netif_running(dev)) 888e894d720SHariprasad Shenai return t4_link_l1cfg(p->adapter, p->adapter->mbox, p->tx_chan, 889812034f1SHariprasad Shenai lc); 890812034f1SHariprasad Shenai return 0; 891812034f1SHariprasad Shenai } 892812034f1SHariprasad Shenai 893812034f1SHariprasad Shenai static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) 894812034f1SHariprasad Shenai { 895812034f1SHariprasad Shenai const struct port_info *pi = netdev_priv(dev); 896812034f1SHariprasad Shenai const struct sge *s = &pi->adapter->sge; 897812034f1SHariprasad Shenai 898812034f1SHariprasad Shenai e->rx_max_pending = MAX_RX_BUFFERS; 899812034f1SHariprasad Shenai e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; 900812034f1SHariprasad Shenai e->rx_jumbo_max_pending = 0; 901812034f1SHariprasad Shenai e->tx_max_pending = MAX_TXQ_ENTRIES; 902812034f1SHariprasad Shenai 903812034f1SHariprasad Shenai e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; 904812034f1SHariprasad Shenai e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; 905812034f1SHariprasad Shenai e->rx_jumbo_pending = 0; 906812034f1SHariprasad Shenai e->tx_pending = s->ethtxq[pi->first_qset].q.size; 907812034f1SHariprasad Shenai } 908812034f1SHariprasad Shenai 909812034f1SHariprasad Shenai static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) 910812034f1SHariprasad Shenai { 911812034f1SHariprasad Shenai int i; 912812034f1SHariprasad Shenai const struct port_info *pi = netdev_priv(dev); 913812034f1SHariprasad Shenai struct adapter *adapter = pi->adapter; 914812034f1SHariprasad Shenai struct sge *s = &adapter->sge; 915812034f1SHariprasad Shenai 916812034f1SHariprasad Shenai if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || 917812034f1SHariprasad Shenai e->tx_pending > MAX_TXQ_ENTRIES || 918812034f1SHariprasad Shenai e->rx_mini_pending > MAX_RSPQ_ENTRIES || 919812034f1SHariprasad Shenai e->rx_mini_pending < MIN_RSPQ_ENTRIES || 920812034f1SHariprasad Shenai e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) 921812034f1SHariprasad Shenai return -EINVAL; 922812034f1SHariprasad Shenai 92380f61f19SArjun Vynipadath if (adapter->flags & CXGB4_FULL_INIT_DONE) 924812034f1SHariprasad Shenai return -EBUSY; 925812034f1SHariprasad Shenai 926812034f1SHariprasad Shenai for (i = 0; i < pi->nqsets; ++i) { 927812034f1SHariprasad Shenai s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; 928812034f1SHariprasad Shenai s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; 929812034f1SHariprasad Shenai s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; 930812034f1SHariprasad Shenai } 931812034f1SHariprasad Shenai return 0; 932812034f1SHariprasad Shenai } 933812034f1SHariprasad Shenai 934812034f1SHariprasad Shenai /** 935812034f1SHariprasad Shenai * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! 936812034f1SHariprasad Shenai * @dev: the network device 937812034f1SHariprasad Shenai * @us: the hold-off time in us, or 0 to disable timer 938812034f1SHariprasad Shenai * @cnt: the hold-off packet count, or 0 to disable counter 939812034f1SHariprasad Shenai * 940812034f1SHariprasad Shenai * Set the RX interrupt hold-off parameters for a network device. 941812034f1SHariprasad Shenai */ 942812034f1SHariprasad Shenai static int set_rx_intr_params(struct net_device *dev, 943812034f1SHariprasad Shenai unsigned int us, unsigned int cnt) 944812034f1SHariprasad Shenai { 945812034f1SHariprasad Shenai int i, err; 946812034f1SHariprasad Shenai struct port_info *pi = netdev_priv(dev); 947812034f1SHariprasad Shenai struct adapter *adap = pi->adapter; 948812034f1SHariprasad Shenai struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; 949812034f1SHariprasad Shenai 950812034f1SHariprasad Shenai for (i = 0; i < pi->nqsets; i++, q++) { 951812034f1SHariprasad Shenai err = cxgb4_set_rspq_intr_params(&q->rspq, us, cnt); 952812034f1SHariprasad Shenai if (err) 953812034f1SHariprasad Shenai return err; 954812034f1SHariprasad Shenai } 955812034f1SHariprasad Shenai return 0; 956812034f1SHariprasad Shenai } 957812034f1SHariprasad Shenai 958812034f1SHariprasad Shenai static int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) 959812034f1SHariprasad Shenai { 960812034f1SHariprasad Shenai int i; 961812034f1SHariprasad Shenai struct port_info *pi = netdev_priv(dev); 962812034f1SHariprasad Shenai struct adapter *adap = pi->adapter; 963812034f1SHariprasad Shenai struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; 964812034f1SHariprasad Shenai 965812034f1SHariprasad Shenai for (i = 0; i < pi->nqsets; i++, q++) 966812034f1SHariprasad Shenai q->rspq.adaptive_rx = adaptive_rx; 967812034f1SHariprasad Shenai 968812034f1SHariprasad Shenai return 0; 969812034f1SHariprasad Shenai } 970812034f1SHariprasad Shenai 971812034f1SHariprasad Shenai static int get_adaptive_rx_setting(struct net_device *dev) 972812034f1SHariprasad Shenai { 973812034f1SHariprasad Shenai struct port_info *pi = netdev_priv(dev); 974812034f1SHariprasad Shenai struct adapter *adap = pi->adapter; 975812034f1SHariprasad Shenai struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; 976812034f1SHariprasad Shenai 977812034f1SHariprasad Shenai return q->rspq.adaptive_rx; 978812034f1SHariprasad Shenai } 979812034f1SHariprasad Shenai 980543a1b85SVishal Kulkarni /* Return the current global Adapter SGE Doorbell Queue Timer Tick for all 981543a1b85SVishal Kulkarni * Ethernet TX Queues. 982543a1b85SVishal Kulkarni */ 983543a1b85SVishal Kulkarni static int get_dbqtimer_tick(struct net_device *dev) 984812034f1SHariprasad Shenai { 985543a1b85SVishal Kulkarni struct port_info *pi = netdev_priv(dev); 986543a1b85SVishal Kulkarni struct adapter *adap = pi->adapter; 987543a1b85SVishal Kulkarni 98880f61f19SArjun Vynipadath if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 989543a1b85SVishal Kulkarni return 0; 990543a1b85SVishal Kulkarni 991543a1b85SVishal Kulkarni return adap->sge.dbqtimer_tick; 992543a1b85SVishal Kulkarni } 993543a1b85SVishal Kulkarni 994543a1b85SVishal Kulkarni /* Return the SGE Doorbell Queue Timer Value for the Ethernet TX Queues 995543a1b85SVishal Kulkarni * associated with a Network Device. 996543a1b85SVishal Kulkarni */ 997543a1b85SVishal Kulkarni static int get_dbqtimer(struct net_device *dev) 998543a1b85SVishal Kulkarni { 999543a1b85SVishal Kulkarni struct port_info *pi = netdev_priv(dev); 1000543a1b85SVishal Kulkarni struct adapter *adap = pi->adapter; 1001543a1b85SVishal Kulkarni struct sge_eth_txq *txq; 1002543a1b85SVishal Kulkarni 1003543a1b85SVishal Kulkarni txq = &adap->sge.ethtxq[pi->first_qset]; 1004543a1b85SVishal Kulkarni 100580f61f19SArjun Vynipadath if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 1006543a1b85SVishal Kulkarni return 0; 1007543a1b85SVishal Kulkarni 1008543a1b85SVishal Kulkarni /* all of the TX Queues use the same Timer Index */ 1009543a1b85SVishal Kulkarni return adap->sge.dbqtimer_val[txq->dbqtimerix]; 1010543a1b85SVishal Kulkarni } 1011543a1b85SVishal Kulkarni 1012543a1b85SVishal Kulkarni /* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX 1013543a1b85SVishal Kulkarni * Queues. This is the fundamental "Tick" that sets the scale of values which 1014543a1b85SVishal Kulkarni * can be used. Individual Ethernet TX Queues index into a relatively small 1015543a1b85SVishal Kulkarni * array of Tick Multipliers. Changing the base Tick will thus change all of 1016543a1b85SVishal Kulkarni * the resulting Timer Values associated with those multipliers for all 1017543a1b85SVishal Kulkarni * Ethernet TX Queues. 1018543a1b85SVishal Kulkarni */ 1019543a1b85SVishal Kulkarni static int set_dbqtimer_tick(struct net_device *dev, int usecs) 1020543a1b85SVishal Kulkarni { 1021543a1b85SVishal Kulkarni struct port_info *pi = netdev_priv(dev); 1022543a1b85SVishal Kulkarni struct adapter *adap = pi->adapter; 1023543a1b85SVishal Kulkarni struct sge *s = &adap->sge; 1024543a1b85SVishal Kulkarni u32 param, val; 1025543a1b85SVishal Kulkarni int ret; 1026543a1b85SVishal Kulkarni 102780f61f19SArjun Vynipadath if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 1028543a1b85SVishal Kulkarni return 0; 1029543a1b85SVishal Kulkarni 1030543a1b85SVishal Kulkarni /* return early if it's the same Timer Tick we're already using */ 1031543a1b85SVishal Kulkarni if (s->dbqtimer_tick == usecs) 1032543a1b85SVishal Kulkarni return 0; 1033543a1b85SVishal Kulkarni 1034543a1b85SVishal Kulkarni /* attempt to set the new Timer Tick value */ 1035543a1b85SVishal Kulkarni param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 1036543a1b85SVishal Kulkarni FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK)); 1037543a1b85SVishal Kulkarni val = usecs; 1038543a1b85SVishal Kulkarni ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 1039543a1b85SVishal Kulkarni if (ret) 1040543a1b85SVishal Kulkarni return ret; 1041543a1b85SVishal Kulkarni s->dbqtimer_tick = usecs; 1042543a1b85SVishal Kulkarni 1043543a1b85SVishal Kulkarni /* if successful, reread resulting dependent Timer values */ 1044543a1b85SVishal Kulkarni ret = t4_read_sge_dbqtimers(adap, ARRAY_SIZE(s->dbqtimer_val), 1045543a1b85SVishal Kulkarni s->dbqtimer_val); 1046543a1b85SVishal Kulkarni return ret; 1047543a1b85SVishal Kulkarni } 1048543a1b85SVishal Kulkarni 1049543a1b85SVishal Kulkarni /* Set the SGE Doorbell Queue Timer Value for the Ethernet TX Queues 1050543a1b85SVishal Kulkarni * associated with a Network Device. There is a relatively small array of 1051543a1b85SVishal Kulkarni * possible Timer Values so we need to pick the closest value available. 1052543a1b85SVishal Kulkarni */ 1053543a1b85SVishal Kulkarni static int set_dbqtimer(struct net_device *dev, int usecs) 1054543a1b85SVishal Kulkarni { 1055543a1b85SVishal Kulkarni int qix, timerix, min_timerix, delta, min_delta; 1056543a1b85SVishal Kulkarni struct port_info *pi = netdev_priv(dev); 1057543a1b85SVishal Kulkarni struct adapter *adap = pi->adapter; 1058543a1b85SVishal Kulkarni struct sge *s = &adap->sge; 1059543a1b85SVishal Kulkarni struct sge_eth_txq *txq; 1060543a1b85SVishal Kulkarni u32 param, val; 1061543a1b85SVishal Kulkarni int ret; 1062543a1b85SVishal Kulkarni 106380f61f19SArjun Vynipadath if (!(adap->flags & CXGB4_SGE_DBQ_TIMER)) 1064543a1b85SVishal Kulkarni return 0; 1065543a1b85SVishal Kulkarni 1066543a1b85SVishal Kulkarni /* Find the SGE Doorbell Timer Value that's closest to the requested 1067543a1b85SVishal Kulkarni * value. 1068543a1b85SVishal Kulkarni */ 1069543a1b85SVishal Kulkarni min_delta = INT_MAX; 1070543a1b85SVishal Kulkarni min_timerix = 0; 1071543a1b85SVishal Kulkarni for (timerix = 0; timerix < ARRAY_SIZE(s->dbqtimer_val); timerix++) { 1072543a1b85SVishal Kulkarni delta = s->dbqtimer_val[timerix] - usecs; 1073543a1b85SVishal Kulkarni if (delta < 0) 1074543a1b85SVishal Kulkarni delta = -delta; 1075543a1b85SVishal Kulkarni if (delta < min_delta) { 1076543a1b85SVishal Kulkarni min_delta = delta; 1077543a1b85SVishal Kulkarni min_timerix = timerix; 1078543a1b85SVishal Kulkarni } 1079543a1b85SVishal Kulkarni } 1080543a1b85SVishal Kulkarni 1081543a1b85SVishal Kulkarni /* Return early if it's the same Timer Index we're already using. 1082543a1b85SVishal Kulkarni * We use the same Timer Index for all of the TX Queues for an 1083543a1b85SVishal Kulkarni * interface so it's only necessary to check the first one. 1084543a1b85SVishal Kulkarni */ 1085543a1b85SVishal Kulkarni txq = &s->ethtxq[pi->first_qset]; 1086543a1b85SVishal Kulkarni if (txq->dbqtimerix == min_timerix) 1087543a1b85SVishal Kulkarni return 0; 1088543a1b85SVishal Kulkarni 1089543a1b85SVishal Kulkarni for (qix = 0; qix < pi->nqsets; qix++, txq++) { 109080f61f19SArjun Vynipadath if (adap->flags & CXGB4_FULL_INIT_DONE) { 1091543a1b85SVishal Kulkarni param = 1092543a1b85SVishal Kulkarni (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 1093543a1b85SVishal Kulkarni FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DMAQ_EQ_TIMERIX) | 1094543a1b85SVishal Kulkarni FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id)); 1095543a1b85SVishal Kulkarni val = min_timerix; 1096543a1b85SVishal Kulkarni ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1097543a1b85SVishal Kulkarni 1, ¶m, &val); 1098543a1b85SVishal Kulkarni if (ret) 1099543a1b85SVishal Kulkarni return ret; 1100543a1b85SVishal Kulkarni } 1101543a1b85SVishal Kulkarni txq->dbqtimerix = min_timerix; 1102543a1b85SVishal Kulkarni } 1103543a1b85SVishal Kulkarni return 0; 1104543a1b85SVishal Kulkarni } 1105543a1b85SVishal Kulkarni 1106543a1b85SVishal Kulkarni /* Set the global Adapter SGE Doorbell Queue Timer Tick for all Ethernet TX 1107543a1b85SVishal Kulkarni * Queues and the Timer Value for the Ethernet TX Queues associated with a 1108543a1b85SVishal Kulkarni * Network Device. Since changing the global Tick changes all of the 1109543a1b85SVishal Kulkarni * available Timer Values, we need to do this first before selecting the 1110543a1b85SVishal Kulkarni * resulting closest Timer Value. Moreover, since the Tick is global, 1111543a1b85SVishal Kulkarni * changing it affects the Timer Values for all Network Devices on the 1112543a1b85SVishal Kulkarni * adapter. So, before changing the Tick, we grab all of the current Timer 1113543a1b85SVishal Kulkarni * Values for other Network Devices on this Adapter and then attempt to select 1114543a1b85SVishal Kulkarni * new Timer Values which are close to the old values ... 1115543a1b85SVishal Kulkarni */ 1116543a1b85SVishal Kulkarni static int set_dbqtimer_tickval(struct net_device *dev, 1117543a1b85SVishal Kulkarni int tick_usecs, int timer_usecs) 1118543a1b85SVishal Kulkarni { 1119543a1b85SVishal Kulkarni struct port_info *pi = netdev_priv(dev); 1120543a1b85SVishal Kulkarni struct adapter *adap = pi->adapter; 1121543a1b85SVishal Kulkarni int timer[MAX_NPORTS]; 1122543a1b85SVishal Kulkarni unsigned int port; 1123543a1b85SVishal Kulkarni int ret; 1124543a1b85SVishal Kulkarni 1125543a1b85SVishal Kulkarni /* Grab the other adapter Network Interface current timers and fill in 1126543a1b85SVishal Kulkarni * the new one for this Network Interface. 1127543a1b85SVishal Kulkarni */ 1128543a1b85SVishal Kulkarni for_each_port(adap, port) 1129543a1b85SVishal Kulkarni if (port == pi->port_id) 1130543a1b85SVishal Kulkarni timer[port] = timer_usecs; 1131543a1b85SVishal Kulkarni else 1132543a1b85SVishal Kulkarni timer[port] = get_dbqtimer(adap->port[port]); 1133543a1b85SVishal Kulkarni 1134543a1b85SVishal Kulkarni /* Change the global Tick first ... */ 1135543a1b85SVishal Kulkarni ret = set_dbqtimer_tick(dev, tick_usecs); 1136543a1b85SVishal Kulkarni if (ret) 1137543a1b85SVishal Kulkarni return ret; 1138543a1b85SVishal Kulkarni 1139543a1b85SVishal Kulkarni /* ... and then set all of the Network Interface Timer Values ... */ 1140543a1b85SVishal Kulkarni for_each_port(adap, port) { 1141543a1b85SVishal Kulkarni ret = set_dbqtimer(adap->port[port], timer[port]); 1142543a1b85SVishal Kulkarni if (ret) 1143543a1b85SVishal Kulkarni return ret; 1144543a1b85SVishal Kulkarni } 1145543a1b85SVishal Kulkarni 1146543a1b85SVishal Kulkarni return 0; 1147543a1b85SVishal Kulkarni } 1148543a1b85SVishal Kulkarni 1149543a1b85SVishal Kulkarni static int set_coalesce(struct net_device *dev, 1150*f3ccfda1SYufeng Mo struct ethtool_coalesce *coalesce, 1151*f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 1152*f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 1153543a1b85SVishal Kulkarni { 1154543a1b85SVishal Kulkarni int ret; 1155543a1b85SVishal Kulkarni 1156543a1b85SVishal Kulkarni set_adaptive_rx_setting(dev, coalesce->use_adaptive_rx_coalesce); 1157543a1b85SVishal Kulkarni 1158543a1b85SVishal Kulkarni ret = set_rx_intr_params(dev, coalesce->rx_coalesce_usecs, 1159543a1b85SVishal Kulkarni coalesce->rx_max_coalesced_frames); 1160543a1b85SVishal Kulkarni if (ret) 1161543a1b85SVishal Kulkarni return ret; 1162543a1b85SVishal Kulkarni 1163543a1b85SVishal Kulkarni return set_dbqtimer_tickval(dev, 1164543a1b85SVishal Kulkarni coalesce->tx_coalesce_usecs_irq, 1165543a1b85SVishal Kulkarni coalesce->tx_coalesce_usecs); 1166812034f1SHariprasad Shenai } 1167812034f1SHariprasad Shenai 1168*f3ccfda1SYufeng Mo static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c, 1169*f3ccfda1SYufeng Mo struct kernel_ethtool_coalesce *kernel_coal, 1170*f3ccfda1SYufeng Mo struct netlink_ext_ack *extack) 1171812034f1SHariprasad Shenai { 1172812034f1SHariprasad Shenai const struct port_info *pi = netdev_priv(dev); 1173812034f1SHariprasad Shenai const struct adapter *adap = pi->adapter; 1174812034f1SHariprasad Shenai const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; 1175812034f1SHariprasad Shenai 1176812034f1SHariprasad Shenai c->rx_coalesce_usecs = qtimer_val(adap, rq); 11771ecc7b7aSHariprasad Shenai c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN_F) ? 1178812034f1SHariprasad Shenai adap->sge.counter_val[rq->pktcnt_idx] : 0; 1179812034f1SHariprasad Shenai c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); 1180543a1b85SVishal Kulkarni c->tx_coalesce_usecs_irq = get_dbqtimer_tick(dev); 1181543a1b85SVishal Kulkarni c->tx_coalesce_usecs = get_dbqtimer(dev); 1182812034f1SHariprasad Shenai return 0; 1183812034f1SHariprasad Shenai } 1184812034f1SHariprasad Shenai 1185812034f1SHariprasad Shenai /* The next two routines implement eeprom read/write from physical addresses. 1186812034f1SHariprasad Shenai */ 1187812034f1SHariprasad Shenai static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) 1188812034f1SHariprasad Shenai { 1189940c9c45SRahul Lakkireddy int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); 1190812034f1SHariprasad Shenai 1191812034f1SHariprasad Shenai if (vaddr >= 0) 1192812034f1SHariprasad Shenai vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); 1193812034f1SHariprasad Shenai return vaddr < 0 ? vaddr : 0; 1194812034f1SHariprasad Shenai } 1195812034f1SHariprasad Shenai 1196812034f1SHariprasad Shenai static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) 1197812034f1SHariprasad Shenai { 1198940c9c45SRahul Lakkireddy int vaddr = t4_eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE); 1199812034f1SHariprasad Shenai 1200812034f1SHariprasad Shenai if (vaddr >= 0) 1201812034f1SHariprasad Shenai vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); 1202812034f1SHariprasad Shenai return vaddr < 0 ? vaddr : 0; 1203812034f1SHariprasad Shenai } 1204812034f1SHariprasad Shenai 1205812034f1SHariprasad Shenai #define EEPROM_MAGIC 0x38E2F10C 1206812034f1SHariprasad Shenai 1207812034f1SHariprasad Shenai static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, 1208812034f1SHariprasad Shenai u8 *data) 1209812034f1SHariprasad Shenai { 1210812034f1SHariprasad Shenai int i, err = 0; 1211812034f1SHariprasad Shenai struct adapter *adapter = netdev2adap(dev); 1212752ade68SMichal Hocko u8 *buf = kvzalloc(EEPROMSIZE, GFP_KERNEL); 1213812034f1SHariprasad Shenai 1214812034f1SHariprasad Shenai if (!buf) 1215812034f1SHariprasad Shenai return -ENOMEM; 1216812034f1SHariprasad Shenai 1217812034f1SHariprasad Shenai e->magic = EEPROM_MAGIC; 1218812034f1SHariprasad Shenai for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) 1219812034f1SHariprasad Shenai err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); 1220812034f1SHariprasad Shenai 1221812034f1SHariprasad Shenai if (!err) 1222812034f1SHariprasad Shenai memcpy(data, buf + e->offset, e->len); 1223752ade68SMichal Hocko kvfree(buf); 1224812034f1SHariprasad Shenai return err; 1225812034f1SHariprasad Shenai } 1226812034f1SHariprasad Shenai 1227812034f1SHariprasad Shenai static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 1228812034f1SHariprasad Shenai u8 *data) 1229812034f1SHariprasad Shenai { 1230812034f1SHariprasad Shenai u8 *buf; 1231812034f1SHariprasad Shenai int err = 0; 1232812034f1SHariprasad Shenai u32 aligned_offset, aligned_len, *p; 1233812034f1SHariprasad Shenai struct adapter *adapter = netdev2adap(dev); 1234812034f1SHariprasad Shenai 1235812034f1SHariprasad Shenai if (eeprom->magic != EEPROM_MAGIC) 1236812034f1SHariprasad Shenai return -EINVAL; 1237812034f1SHariprasad Shenai 1238812034f1SHariprasad Shenai aligned_offset = eeprom->offset & ~3; 1239812034f1SHariprasad Shenai aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; 1240812034f1SHariprasad Shenai 1241b2612722SHariprasad Shenai if (adapter->pf > 0) { 1242b2612722SHariprasad Shenai u32 start = 1024 + adapter->pf * EEPROMPFSIZE; 1243812034f1SHariprasad Shenai 1244812034f1SHariprasad Shenai if (aligned_offset < start || 1245812034f1SHariprasad Shenai aligned_offset + aligned_len > start + EEPROMPFSIZE) 1246812034f1SHariprasad Shenai return -EPERM; 1247812034f1SHariprasad Shenai } 1248812034f1SHariprasad Shenai 1249812034f1SHariprasad Shenai if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { 1250812034f1SHariprasad Shenai /* RMW possibly needed for first or last words. 1251812034f1SHariprasad Shenai */ 1252752ade68SMichal Hocko buf = kvzalloc(aligned_len, GFP_KERNEL); 1253812034f1SHariprasad Shenai if (!buf) 1254812034f1SHariprasad Shenai return -ENOMEM; 1255812034f1SHariprasad Shenai err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); 1256812034f1SHariprasad Shenai if (!err && aligned_len > 4) 1257812034f1SHariprasad Shenai err = eeprom_rd_phys(adapter, 1258812034f1SHariprasad Shenai aligned_offset + aligned_len - 4, 1259812034f1SHariprasad Shenai (u32 *)&buf[aligned_len - 4]); 1260812034f1SHariprasad Shenai if (err) 1261812034f1SHariprasad Shenai goto out; 1262812034f1SHariprasad Shenai memcpy(buf + (eeprom->offset & 3), data, eeprom->len); 1263812034f1SHariprasad Shenai } else { 1264812034f1SHariprasad Shenai buf = data; 1265812034f1SHariprasad Shenai } 1266812034f1SHariprasad Shenai 1267812034f1SHariprasad Shenai err = t4_seeprom_wp(adapter, false); 1268812034f1SHariprasad Shenai if (err) 1269812034f1SHariprasad Shenai goto out; 1270812034f1SHariprasad Shenai 1271812034f1SHariprasad Shenai for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 1272812034f1SHariprasad Shenai err = eeprom_wr_phys(adapter, aligned_offset, *p); 1273812034f1SHariprasad Shenai aligned_offset += 4; 1274812034f1SHariprasad Shenai } 1275812034f1SHariprasad Shenai 1276812034f1SHariprasad Shenai if (!err) 1277812034f1SHariprasad Shenai err = t4_seeprom_wp(adapter, true); 1278812034f1SHariprasad Shenai out: 1279812034f1SHariprasad Shenai if (buf != data) 1280752ade68SMichal Hocko kvfree(buf); 1281812034f1SHariprasad Shenai return err; 1282812034f1SHariprasad Shenai } 1283812034f1SHariprasad Shenai 1284d5002c9aSVishal Kulkarni static int cxgb4_ethtool_flash_bootcfg(struct net_device *netdev, 1285d5002c9aSVishal Kulkarni const u8 *data, u32 size) 1286d5002c9aSVishal Kulkarni { 1287d5002c9aSVishal Kulkarni struct adapter *adap = netdev2adap(netdev); 1288d5002c9aSVishal Kulkarni int ret; 1289d5002c9aSVishal Kulkarni 1290d5002c9aSVishal Kulkarni ret = t4_load_bootcfg(adap, data, size); 1291d5002c9aSVishal Kulkarni if (ret) 1292d5002c9aSVishal Kulkarni dev_err(adap->pdev_dev, "Failed to load boot cfg image\n"); 1293d5002c9aSVishal Kulkarni 1294d5002c9aSVishal Kulkarni return ret; 1295d5002c9aSVishal Kulkarni } 1296d5002c9aSVishal Kulkarni 129755088355SVishal Kulkarni static int cxgb4_ethtool_flash_boot(struct net_device *netdev, 129855088355SVishal Kulkarni const u8 *bdata, u32 size) 129955088355SVishal Kulkarni { 130055088355SVishal Kulkarni struct adapter *adap = netdev2adap(netdev); 130155088355SVishal Kulkarni unsigned int offset; 130255088355SVishal Kulkarni u8 *data; 130355088355SVishal Kulkarni int ret; 130455088355SVishal Kulkarni 130555088355SVishal Kulkarni data = kmemdup(bdata, size, GFP_KERNEL); 130655088355SVishal Kulkarni if (!data) 130755088355SVishal Kulkarni return -ENOMEM; 130855088355SVishal Kulkarni 130955088355SVishal Kulkarni offset = OFFSET_G(t4_read_reg(adap, PF_REG(0, PCIE_PF_EXPROM_OFST_A))); 131055088355SVishal Kulkarni 131155088355SVishal Kulkarni ret = t4_load_boot(adap, data, offset, size); 131255088355SVishal Kulkarni if (ret) 131355088355SVishal Kulkarni dev_err(adap->pdev_dev, "Failed to load boot image\n"); 131455088355SVishal Kulkarni 131555088355SVishal Kulkarni kfree(data); 131655088355SVishal Kulkarni return ret; 131755088355SVishal Kulkarni } 131855088355SVishal Kulkarni 13194ee339e1SVishal Kulkarni #define CXGB4_PHY_SIG 0x130000ea 13204ee339e1SVishal Kulkarni 13214ee339e1SVishal Kulkarni static int cxgb4_validate_phy_image(const u8 *data, u32 *size) 13224ee339e1SVishal Kulkarni { 13234ee339e1SVishal Kulkarni struct cxgb4_fw_data *header; 13244ee339e1SVishal Kulkarni 13254ee339e1SVishal Kulkarni header = (struct cxgb4_fw_data *)data; 13264ee339e1SVishal Kulkarni if (be32_to_cpu(header->signature) != CXGB4_PHY_SIG) 13274ee339e1SVishal Kulkarni return -EINVAL; 13284ee339e1SVishal Kulkarni 13294ee339e1SVishal Kulkarni return 0; 13304ee339e1SVishal Kulkarni } 13314ee339e1SVishal Kulkarni 13324ee339e1SVishal Kulkarni static int cxgb4_ethtool_flash_phy(struct net_device *netdev, 13334ee339e1SVishal Kulkarni const u8 *data, u32 size) 13344ee339e1SVishal Kulkarni { 13354ee339e1SVishal Kulkarni struct adapter *adap = netdev2adap(netdev); 13364ee339e1SVishal Kulkarni int ret; 13374ee339e1SVishal Kulkarni 13384ee339e1SVishal Kulkarni ret = cxgb4_validate_phy_image(data, NULL); 13394ee339e1SVishal Kulkarni if (ret) { 13404ee339e1SVishal Kulkarni dev_err(adap->pdev_dev, "PHY signature mismatch\n"); 13414ee339e1SVishal Kulkarni return ret; 13424ee339e1SVishal Kulkarni } 13434ee339e1SVishal Kulkarni 13446d297540SRahul Lakkireddy /* We have to RESET the chip/firmware because we need the 13456d297540SRahul Lakkireddy * chip in uninitialized state for loading new PHY image. 13466d297540SRahul Lakkireddy * Otherwise, the running firmware will only store the PHY 13476d297540SRahul Lakkireddy * image in local RAM which will be lost after next reset. 13486d297540SRahul Lakkireddy */ 13496d297540SRahul Lakkireddy ret = t4_fw_reset(adap, adap->mbox, PIORSTMODE_F | PIORST_F); 13506d297540SRahul Lakkireddy if (ret < 0) { 13516d297540SRahul Lakkireddy dev_err(adap->pdev_dev, 13526d297540SRahul Lakkireddy "Set FW to RESET for flashing PHY FW failed. ret: %d\n", 13536d297540SRahul Lakkireddy ret); 13544ee339e1SVishal Kulkarni return ret; 13554ee339e1SVishal Kulkarni } 13564ee339e1SVishal Kulkarni 13576d297540SRahul Lakkireddy ret = t4_load_phy_fw(adap, MEMWIN_NIC, NULL, data, size); 13586d297540SRahul Lakkireddy if (ret < 0) { 13596d297540SRahul Lakkireddy dev_err(adap->pdev_dev, "Failed to load PHY FW. ret: %d\n", 13606d297540SRahul Lakkireddy ret); 13616d297540SRahul Lakkireddy return ret; 13626d297540SRahul Lakkireddy } 13636d297540SRahul Lakkireddy 13646d297540SRahul Lakkireddy return 0; 13656d297540SRahul Lakkireddy } 13666d297540SRahul Lakkireddy 13673893c905SVishal Kulkarni static int cxgb4_ethtool_flash_fw(struct net_device *netdev, 13683893c905SVishal Kulkarni const u8 *data, u32 size) 1369812034f1SHariprasad Shenai { 1370812034f1SHariprasad Shenai struct adapter *adap = netdev2adap(netdev); 1371812034f1SHariprasad Shenai unsigned int mbox = PCIE_FW_MASTER_M + 1; 13723893c905SVishal Kulkarni int ret; 13733893c905SVishal Kulkarni 13743893c905SVishal Kulkarni /* If the adapter has been fully initialized then we'll go ahead and 13753893c905SVishal Kulkarni * try to get the firmware's cooperation in upgrading to the new 13763893c905SVishal Kulkarni * firmware image otherwise we'll try to do the entire job from the 13773893c905SVishal Kulkarni * host ... and we always "force" the operation in this path. 13783893c905SVishal Kulkarni */ 13793893c905SVishal Kulkarni if (adap->flags & CXGB4_FULL_INIT_DONE) 13803893c905SVishal Kulkarni mbox = adap->mbox; 13813893c905SVishal Kulkarni 13823893c905SVishal Kulkarni ret = t4_fw_upgrade(adap, mbox, data, size, 1); 13833893c905SVishal Kulkarni if (ret) 13843893c905SVishal Kulkarni dev_err(adap->pdev_dev, 13853893c905SVishal Kulkarni "Failed to flash firmware\n"); 13863893c905SVishal Kulkarni 13873893c905SVishal Kulkarni return ret; 13883893c905SVishal Kulkarni } 13893893c905SVishal Kulkarni 13903893c905SVishal Kulkarni static int cxgb4_ethtool_flash_region(struct net_device *netdev, 13913893c905SVishal Kulkarni const u8 *data, u32 size, u32 region) 13923893c905SVishal Kulkarni { 13933893c905SVishal Kulkarni struct adapter *adap = netdev2adap(netdev); 13943893c905SVishal Kulkarni int ret; 13953893c905SVishal Kulkarni 13963893c905SVishal Kulkarni switch (region) { 13973893c905SVishal Kulkarni case CXGB4_ETHTOOL_FLASH_FW: 13983893c905SVishal Kulkarni ret = cxgb4_ethtool_flash_fw(netdev, data, size); 13993893c905SVishal Kulkarni break; 14004ee339e1SVishal Kulkarni case CXGB4_ETHTOOL_FLASH_PHY: 14014ee339e1SVishal Kulkarni ret = cxgb4_ethtool_flash_phy(netdev, data, size); 14024ee339e1SVishal Kulkarni break; 140355088355SVishal Kulkarni case CXGB4_ETHTOOL_FLASH_BOOT: 140455088355SVishal Kulkarni ret = cxgb4_ethtool_flash_boot(netdev, data, size); 140555088355SVishal Kulkarni break; 1406d5002c9aSVishal Kulkarni case CXGB4_ETHTOOL_FLASH_BOOTCFG: 1407d5002c9aSVishal Kulkarni ret = cxgb4_ethtool_flash_bootcfg(netdev, data, size); 1408d5002c9aSVishal Kulkarni break; 14093893c905SVishal Kulkarni default: 14103893c905SVishal Kulkarni ret = -EOPNOTSUPP; 14113893c905SVishal Kulkarni break; 14123893c905SVishal Kulkarni } 14133893c905SVishal Kulkarni 14143893c905SVishal Kulkarni if (!ret) 14153893c905SVishal Kulkarni dev_info(adap->pdev_dev, 14163893c905SVishal Kulkarni "loading %s successful, reload cxgb4 driver\n", 14173893c905SVishal Kulkarni flash_region_strings[region]); 14183893c905SVishal Kulkarni return ret; 14193893c905SVishal Kulkarni } 14203893c905SVishal Kulkarni 14213893c905SVishal Kulkarni #define CXGB4_FW_SIG 0x4368656c 14223893c905SVishal Kulkarni #define CXGB4_FW_SIG_OFFSET 0x160 14233893c905SVishal Kulkarni 14243893c905SVishal Kulkarni static int cxgb4_validate_fw_image(const u8 *data, u32 *size) 14253893c905SVishal Kulkarni { 14263893c905SVishal Kulkarni struct cxgb4_fw_data *header; 14273893c905SVishal Kulkarni 14283893c905SVishal Kulkarni header = (struct cxgb4_fw_data *)&data[CXGB4_FW_SIG_OFFSET]; 14293893c905SVishal Kulkarni if (be32_to_cpu(header->signature) != CXGB4_FW_SIG) 14303893c905SVishal Kulkarni return -EINVAL; 14313893c905SVishal Kulkarni 14323893c905SVishal Kulkarni if (size) 14333893c905SVishal Kulkarni *size = be16_to_cpu(((struct fw_hdr *)data)->len512) * 512; 14343893c905SVishal Kulkarni 14353893c905SVishal Kulkarni return 0; 14363893c905SVishal Kulkarni } 14373893c905SVishal Kulkarni 1438d5002c9aSVishal Kulkarni static int cxgb4_validate_bootcfg_image(const u8 *data, u32 *size) 1439d5002c9aSVishal Kulkarni { 1440d5002c9aSVishal Kulkarni struct cxgb4_bootcfg_data *header; 1441d5002c9aSVishal Kulkarni 1442d5002c9aSVishal Kulkarni header = (struct cxgb4_bootcfg_data *)data; 1443d5002c9aSVishal Kulkarni if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) 1444d5002c9aSVishal Kulkarni return -EINVAL; 1445d5002c9aSVishal Kulkarni 1446d5002c9aSVishal Kulkarni return 0; 1447d5002c9aSVishal Kulkarni } 1448d5002c9aSVishal Kulkarni 144955088355SVishal Kulkarni static int cxgb4_validate_boot_image(const u8 *data, u32 *size) 145055088355SVishal Kulkarni { 145155088355SVishal Kulkarni struct cxgb4_pci_exp_rom_header *exp_header; 145255088355SVishal Kulkarni struct cxgb4_pcir_data *pcir_header; 145355088355SVishal Kulkarni struct legacy_pci_rom_hdr *header; 145455088355SVishal Kulkarni const u8 *cur_header = data; 145555088355SVishal Kulkarni u16 pcir_offset; 145655088355SVishal Kulkarni 145755088355SVishal Kulkarni exp_header = (struct cxgb4_pci_exp_rom_header *)data; 145855088355SVishal Kulkarni 145955088355SVishal Kulkarni if (le16_to_cpu(exp_header->signature) != BOOT_SIGNATURE) 146055088355SVishal Kulkarni return -EINVAL; 146155088355SVishal Kulkarni 146255088355SVishal Kulkarni if (size) { 146355088355SVishal Kulkarni do { 146455088355SVishal Kulkarni header = (struct legacy_pci_rom_hdr *)cur_header; 146555088355SVishal Kulkarni pcir_offset = le16_to_cpu(header->pcir_offset); 146655088355SVishal Kulkarni pcir_header = (struct cxgb4_pcir_data *)(cur_header + 146755088355SVishal Kulkarni pcir_offset); 146855088355SVishal Kulkarni 146955088355SVishal Kulkarni *size += header->size512 * 512; 147055088355SVishal Kulkarni cur_header += header->size512 * 512; 147155088355SVishal Kulkarni } while (!(pcir_header->indicator & CXGB4_HDR_INDI)); 147255088355SVishal Kulkarni } 147355088355SVishal Kulkarni 147455088355SVishal Kulkarni return 0; 147555088355SVishal Kulkarni } 147655088355SVishal Kulkarni 14773893c905SVishal Kulkarni static int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size) 14783893c905SVishal Kulkarni { 14793893c905SVishal Kulkarni if (!cxgb4_validate_fw_image(data, size)) 14803893c905SVishal Kulkarni return CXGB4_ETHTOOL_FLASH_FW; 148155088355SVishal Kulkarni if (!cxgb4_validate_boot_image(data, size)) 148255088355SVishal Kulkarni return CXGB4_ETHTOOL_FLASH_BOOT; 14834ee339e1SVishal Kulkarni if (!cxgb4_validate_phy_image(data, size)) 14844ee339e1SVishal Kulkarni return CXGB4_ETHTOOL_FLASH_PHY; 1485d5002c9aSVishal Kulkarni if (!cxgb4_validate_bootcfg_image(data, size)) 1486d5002c9aSVishal Kulkarni return CXGB4_ETHTOOL_FLASH_BOOTCFG; 14873893c905SVishal Kulkarni 14883893c905SVishal Kulkarni return -EOPNOTSUPP; 14893893c905SVishal Kulkarni } 14903893c905SVishal Kulkarni 14913893c905SVishal Kulkarni static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) 14923893c905SVishal Kulkarni { 14933893c905SVishal Kulkarni struct adapter *adap = netdev2adap(netdev); 14943893c905SVishal Kulkarni const struct firmware *fw; 1495402b7645SHariprasad Shenai unsigned int master; 1496402b7645SHariprasad Shenai u8 master_vld = 0; 14973893c905SVishal Kulkarni const u8 *fw_data; 14983893c905SVishal Kulkarni size_t fw_size; 14993893c905SVishal Kulkarni u32 size = 0; 15003893c905SVishal Kulkarni u32 pcie_fw; 15013893c905SVishal Kulkarni int region; 15023893c905SVishal Kulkarni int ret; 1503402b7645SHariprasad Shenai 1504402b7645SHariprasad Shenai pcie_fw = t4_read_reg(adap, PCIE_FW_A); 1505402b7645SHariprasad Shenai master = PCIE_FW_MASTER_G(pcie_fw); 1506402b7645SHariprasad Shenai if (pcie_fw & PCIE_FW_MASTER_VLD_F) 1507402b7645SHariprasad Shenai master_vld = 1; 1508402b7645SHariprasad Shenai /* if csiostor is the master return */ 1509402b7645SHariprasad Shenai if (master_vld && (master != adap->pf)) { 1510402b7645SHariprasad Shenai dev_warn(adap->pdev_dev, 1511402b7645SHariprasad Shenai "cxgb4 driver needs to be loaded as MASTER to support FW flash\n"); 1512402b7645SHariprasad Shenai return -EOPNOTSUPP; 1513402b7645SHariprasad Shenai } 1514812034f1SHariprasad Shenai 1515812034f1SHariprasad Shenai ef->data[sizeof(ef->data) - 1] = '\0'; 1516812034f1SHariprasad Shenai ret = request_firmware(&fw, ef->data, adap->pdev_dev); 1517812034f1SHariprasad Shenai if (ret < 0) 1518812034f1SHariprasad Shenai return ret; 1519812034f1SHariprasad Shenai 15203893c905SVishal Kulkarni fw_data = fw->data; 15213893c905SVishal Kulkarni fw_size = fw->size; 15223893c905SVishal Kulkarni if (ef->region == ETHTOOL_FLASH_ALL_REGIONS) { 15233893c905SVishal Kulkarni while (fw_size > 0) { 15243893c905SVishal Kulkarni size = 0; 15253893c905SVishal Kulkarni region = cxgb4_ethtool_get_flash_region(fw_data, &size); 15263893c905SVishal Kulkarni if (region < 0 || !size) { 15273893c905SVishal Kulkarni ret = region; 15283893c905SVishal Kulkarni goto out_free_fw; 15293893c905SVishal Kulkarni } 1530812034f1SHariprasad Shenai 15313893c905SVishal Kulkarni ret = cxgb4_ethtool_flash_region(netdev, fw_data, size, 15323893c905SVishal Kulkarni region); 15333893c905SVishal Kulkarni if (ret) 15343893c905SVishal Kulkarni goto out_free_fw; 15353893c905SVishal Kulkarni 15363893c905SVishal Kulkarni fw_data += size; 15373893c905SVishal Kulkarni fw_size -= size; 15383893c905SVishal Kulkarni } 15393893c905SVishal Kulkarni } else { 15403893c905SVishal Kulkarni ret = cxgb4_ethtool_flash_region(netdev, fw_data, fw_size, 15413893c905SVishal Kulkarni ef->region); 15423893c905SVishal Kulkarni } 15433893c905SVishal Kulkarni 15443893c905SVishal Kulkarni out_free_fw: 1545812034f1SHariprasad Shenai release_firmware(fw); 1546812034f1SHariprasad Shenai return ret; 1547812034f1SHariprasad Shenai } 1548812034f1SHariprasad Shenai 15495e2a5ebcSHariprasad Shenai static int get_ts_info(struct net_device *dev, struct ethtool_ts_info *ts_info) 15505e2a5ebcSHariprasad Shenai { 1551c3ff08ebSAtul Gupta struct port_info *pi = netdev_priv(dev); 1552c3ff08ebSAtul Gupta struct adapter *adapter = pi->adapter; 1553c3ff08ebSAtul Gupta 15545e2a5ebcSHariprasad Shenai ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 15555e2a5ebcSHariprasad Shenai SOF_TIMESTAMPING_RX_SOFTWARE | 15565e2a5ebcSHariprasad Shenai SOF_TIMESTAMPING_SOFTWARE; 15575e2a5ebcSHariprasad Shenai 15585e2a5ebcSHariprasad Shenai ts_info->so_timestamping |= SOF_TIMESTAMPING_RX_HARDWARE | 1559c3ff08ebSAtul Gupta SOF_TIMESTAMPING_TX_HARDWARE | 15605e2a5ebcSHariprasad Shenai SOF_TIMESTAMPING_RAW_HARDWARE; 15615e2a5ebcSHariprasad Shenai 1562c3ff08ebSAtul Gupta ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | 1563c3ff08ebSAtul Gupta (1 << HWTSTAMP_TX_ON); 1564c3ff08ebSAtul Gupta 1565c3ff08ebSAtul Gupta ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 1566c3ff08ebSAtul Gupta (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | 1567c3ff08ebSAtul Gupta (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | 1568c3ff08ebSAtul Gupta (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | 1569c3ff08ebSAtul Gupta (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | 1570c3ff08ebSAtul Gupta (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); 1571c3ff08ebSAtul Gupta 1572c3ff08ebSAtul Gupta if (adapter->ptp_clock) 1573c3ff08ebSAtul Gupta ts_info->phc_index = ptp_clock_index(adapter->ptp_clock); 1574c3ff08ebSAtul Gupta else 15755e2a5ebcSHariprasad Shenai ts_info->phc_index = -1; 15765e2a5ebcSHariprasad Shenai 15775e2a5ebcSHariprasad Shenai return 0; 15785e2a5ebcSHariprasad Shenai } 15795e2a5ebcSHariprasad Shenai 1580812034f1SHariprasad Shenai static u32 get_rss_table_size(struct net_device *dev) 1581812034f1SHariprasad Shenai { 1582812034f1SHariprasad Shenai const struct port_info *pi = netdev_priv(dev); 1583812034f1SHariprasad Shenai 1584812034f1SHariprasad Shenai return pi->rss_size; 1585812034f1SHariprasad Shenai } 1586812034f1SHariprasad Shenai 1587812034f1SHariprasad Shenai static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) 1588812034f1SHariprasad Shenai { 1589812034f1SHariprasad Shenai const struct port_info *pi = netdev_priv(dev); 1590812034f1SHariprasad Shenai unsigned int n = pi->rss_size; 1591812034f1SHariprasad Shenai 1592812034f1SHariprasad Shenai if (hfunc) 1593812034f1SHariprasad Shenai *hfunc = ETH_RSS_HASH_TOP; 1594812034f1SHariprasad Shenai if (!p) 1595812034f1SHariprasad Shenai return 0; 1596812034f1SHariprasad Shenai while (n--) 1597812034f1SHariprasad Shenai p[n] = pi->rss[n]; 1598812034f1SHariprasad Shenai return 0; 1599812034f1SHariprasad Shenai } 1600812034f1SHariprasad Shenai 1601812034f1SHariprasad Shenai static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, 1602812034f1SHariprasad Shenai const u8 hfunc) 1603812034f1SHariprasad Shenai { 1604812034f1SHariprasad Shenai unsigned int i; 1605812034f1SHariprasad Shenai struct port_info *pi = netdev_priv(dev); 1606812034f1SHariprasad Shenai 1607812034f1SHariprasad Shenai /* We require at least one supported parameter to be changed and no 1608812034f1SHariprasad Shenai * change in any of the unsupported parameters 1609812034f1SHariprasad Shenai */ 1610812034f1SHariprasad Shenai if (key || 1611812034f1SHariprasad Shenai (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) 1612812034f1SHariprasad Shenai return -EOPNOTSUPP; 1613812034f1SHariprasad Shenai if (!p) 1614812034f1SHariprasad Shenai return 0; 1615812034f1SHariprasad Shenai 16166ac5fe75SHariprasad Shenai /* Interface must be brought up atleast once */ 161780f61f19SArjun Vynipadath if (pi->adapter->flags & CXGB4_FULL_INIT_DONE) { 1618812034f1SHariprasad Shenai for (i = 0; i < pi->rss_size; i++) 1619812034f1SHariprasad Shenai pi->rss[i] = p[i]; 16206ac5fe75SHariprasad Shenai 1621812034f1SHariprasad Shenai return cxgb4_write_rss(pi, pi->rss); 16226ac5fe75SHariprasad Shenai } 16236ac5fe75SHariprasad Shenai 16246ac5fe75SHariprasad Shenai return -EPERM; 1625812034f1SHariprasad Shenai } 1626812034f1SHariprasad Shenai 1627db43b30cSVishal Kulkarni static struct filter_entry *cxgb4_get_filter_entry(struct adapter *adap, 1628db43b30cSVishal Kulkarni u32 ftid) 1629db43b30cSVishal Kulkarni { 1630db43b30cSVishal Kulkarni struct tid_info *t = &adap->tids; 1631db43b30cSVishal Kulkarni 163209427c19SRahul Lakkireddy if (ftid >= t->hpftid_base && ftid < t->hpftid_base + t->nhpftids) 163309427c19SRahul Lakkireddy return &t->hpftid_tab[ftid - t->hpftid_base]; 1634db43b30cSVishal Kulkarni 163509427c19SRahul Lakkireddy if (ftid >= t->ftid_base && ftid < t->ftid_base + t->nftids) 163609427c19SRahul Lakkireddy return &t->ftid_tab[ftid - t->ftid_base]; 163709427c19SRahul Lakkireddy 163809427c19SRahul Lakkireddy return lookup_tid(t, ftid); 1639db43b30cSVishal Kulkarni } 1640db43b30cSVishal Kulkarni 164127ee2993SVishal Kulkarni static void cxgb4_fill_filter_rule(struct ethtool_rx_flow_spec *fs, 164227ee2993SVishal Kulkarni struct ch_filter_specification *dfs) 164327ee2993SVishal Kulkarni { 164427ee2993SVishal Kulkarni switch (dfs->val.proto) { 164527ee2993SVishal Kulkarni case IPPROTO_TCP: 164627ee2993SVishal Kulkarni if (dfs->type) 164727ee2993SVishal Kulkarni fs->flow_type = TCP_V6_FLOW; 164827ee2993SVishal Kulkarni else 164927ee2993SVishal Kulkarni fs->flow_type = TCP_V4_FLOW; 165027ee2993SVishal Kulkarni break; 165127ee2993SVishal Kulkarni case IPPROTO_UDP: 165227ee2993SVishal Kulkarni if (dfs->type) 165327ee2993SVishal Kulkarni fs->flow_type = UDP_V6_FLOW; 165427ee2993SVishal Kulkarni else 165527ee2993SVishal Kulkarni fs->flow_type = UDP_V4_FLOW; 165627ee2993SVishal Kulkarni break; 165727ee2993SVishal Kulkarni } 165827ee2993SVishal Kulkarni 165927ee2993SVishal Kulkarni if (dfs->type) { 166027ee2993SVishal Kulkarni fs->h_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->val.fport); 166127ee2993SVishal Kulkarni fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(dfs->mask.fport); 166227ee2993SVishal Kulkarni fs->h_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->val.lport); 166327ee2993SVishal Kulkarni fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(dfs->mask.lport); 166427ee2993SVishal Kulkarni memcpy(&fs->h_u.tcp_ip6_spec.ip6src, &dfs->val.fip[0], 166527ee2993SVishal Kulkarni sizeof(fs->h_u.tcp_ip6_spec.ip6src)); 166627ee2993SVishal Kulkarni memcpy(&fs->m_u.tcp_ip6_spec.ip6src, &dfs->mask.fip[0], 166727ee2993SVishal Kulkarni sizeof(fs->m_u.tcp_ip6_spec.ip6src)); 166827ee2993SVishal Kulkarni memcpy(&fs->h_u.tcp_ip6_spec.ip6dst, &dfs->val.lip[0], 166927ee2993SVishal Kulkarni sizeof(fs->h_u.tcp_ip6_spec.ip6dst)); 167027ee2993SVishal Kulkarni memcpy(&fs->m_u.tcp_ip6_spec.ip6dst, &dfs->mask.lip[0], 167127ee2993SVishal Kulkarni sizeof(fs->m_u.tcp_ip6_spec.ip6dst)); 167227ee2993SVishal Kulkarni fs->h_u.tcp_ip6_spec.tclass = dfs->val.tos; 167327ee2993SVishal Kulkarni fs->m_u.tcp_ip6_spec.tclass = dfs->mask.tos; 167427ee2993SVishal Kulkarni } else { 167527ee2993SVishal Kulkarni fs->h_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->val.fport); 167627ee2993SVishal Kulkarni fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(dfs->mask.fport); 167727ee2993SVishal Kulkarni fs->h_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->val.lport); 167827ee2993SVishal Kulkarni fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(dfs->mask.lport); 167927ee2993SVishal Kulkarni memcpy(&fs->h_u.tcp_ip4_spec.ip4src, &dfs->val.fip[0], 168027ee2993SVishal Kulkarni sizeof(fs->h_u.tcp_ip4_spec.ip4src)); 168127ee2993SVishal Kulkarni memcpy(&fs->m_u.tcp_ip4_spec.ip4src, &dfs->mask.fip[0], 168227ee2993SVishal Kulkarni sizeof(fs->m_u.tcp_ip4_spec.ip4src)); 168327ee2993SVishal Kulkarni memcpy(&fs->h_u.tcp_ip4_spec.ip4dst, &dfs->val.lip[0], 168427ee2993SVishal Kulkarni sizeof(fs->h_u.tcp_ip4_spec.ip4dst)); 168527ee2993SVishal Kulkarni memcpy(&fs->m_u.tcp_ip4_spec.ip4dst, &dfs->mask.lip[0], 168627ee2993SVishal Kulkarni sizeof(fs->m_u.tcp_ip4_spec.ip4dst)); 168727ee2993SVishal Kulkarni fs->h_u.tcp_ip4_spec.tos = dfs->val.tos; 168827ee2993SVishal Kulkarni fs->m_u.tcp_ip4_spec.tos = dfs->mask.tos; 168927ee2993SVishal Kulkarni } 169027ee2993SVishal Kulkarni fs->h_ext.vlan_tci = cpu_to_be16(dfs->val.ivlan); 169127ee2993SVishal Kulkarni fs->m_ext.vlan_tci = cpu_to_be16(dfs->mask.ivlan); 169227ee2993SVishal Kulkarni fs->flow_type |= FLOW_EXT; 169327ee2993SVishal Kulkarni 169427ee2993SVishal Kulkarni if (dfs->action == FILTER_DROP) 169527ee2993SVishal Kulkarni fs->ring_cookie = RX_CLS_FLOW_DISC; 169627ee2993SVishal Kulkarni else 169727ee2993SVishal Kulkarni fs->ring_cookie = dfs->iq; 169827ee2993SVishal Kulkarni } 169927ee2993SVishal Kulkarni 170027ee2993SVishal Kulkarni static int cxgb4_ntuple_get_filter(struct net_device *dev, 170127ee2993SVishal Kulkarni struct ethtool_rxnfc *cmd, 170227ee2993SVishal Kulkarni unsigned int loc) 170327ee2993SVishal Kulkarni { 170427ee2993SVishal Kulkarni const struct port_info *pi = netdev_priv(dev); 170527ee2993SVishal Kulkarni struct adapter *adap = netdev2adap(dev); 170627ee2993SVishal Kulkarni struct filter_entry *f; 170727ee2993SVishal Kulkarni int ftid; 170827ee2993SVishal Kulkarni 170927ee2993SVishal Kulkarni if (!(adap->flags & CXGB4_FULL_INIT_DONE)) 171027ee2993SVishal Kulkarni return -EAGAIN; 171127ee2993SVishal Kulkarni 171227ee2993SVishal Kulkarni /* Check for maximum filter range */ 171327ee2993SVishal Kulkarni if (!adap->ethtool_filters) 171427ee2993SVishal Kulkarni return -EOPNOTSUPP; 171527ee2993SVishal Kulkarni 171627ee2993SVishal Kulkarni if (loc >= adap->ethtool_filters->nentries) 171727ee2993SVishal Kulkarni return -ERANGE; 171827ee2993SVishal Kulkarni 171927ee2993SVishal Kulkarni if (!test_bit(loc, adap->ethtool_filters->port[pi->port_id].bmap)) 172027ee2993SVishal Kulkarni return -ENOENT; 172127ee2993SVishal Kulkarni 172227ee2993SVishal Kulkarni ftid = adap->ethtool_filters->port[pi->port_id].loc_array[loc]; 172327ee2993SVishal Kulkarni 172427ee2993SVishal Kulkarni /* Fetch filter_entry */ 172527ee2993SVishal Kulkarni f = cxgb4_get_filter_entry(adap, ftid); 172627ee2993SVishal Kulkarni 172727ee2993SVishal Kulkarni cxgb4_fill_filter_rule(&cmd->fs, &f->fs); 172827ee2993SVishal Kulkarni 172927ee2993SVishal Kulkarni return 0; 173027ee2993SVishal Kulkarni } 173127ee2993SVishal Kulkarni 1732812034f1SHariprasad Shenai static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 1733812034f1SHariprasad Shenai u32 *rules) 1734812034f1SHariprasad Shenai { 1735812034f1SHariprasad Shenai const struct port_info *pi = netdev_priv(dev); 173627ee2993SVishal Kulkarni struct adapter *adap = netdev2adap(dev); 173727ee2993SVishal Kulkarni unsigned int count = 0, index = 0; 173827ee2993SVishal Kulkarni int ret = 0; 1739812034f1SHariprasad Shenai 1740812034f1SHariprasad Shenai switch (info->cmd) { 1741812034f1SHariprasad Shenai case ETHTOOL_GRXFH: { 1742812034f1SHariprasad Shenai unsigned int v = pi->rss_mode; 1743812034f1SHariprasad Shenai 1744812034f1SHariprasad Shenai info->data = 0; 1745812034f1SHariprasad Shenai switch (info->flow_type) { 1746812034f1SHariprasad Shenai case TCP_V4_FLOW: 1747812034f1SHariprasad Shenai if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) 1748812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST | 1749812034f1SHariprasad Shenai RXH_L4_B_0_1 | RXH_L4_B_2_3; 1750812034f1SHariprasad Shenai else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) 1751812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST; 1752812034f1SHariprasad Shenai break; 1753812034f1SHariprasad Shenai case UDP_V4_FLOW: 1754812034f1SHariprasad Shenai if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && 1755812034f1SHariprasad Shenai (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) 1756812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST | 1757812034f1SHariprasad Shenai RXH_L4_B_0_1 | RXH_L4_B_2_3; 1758812034f1SHariprasad Shenai else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) 1759812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST; 1760812034f1SHariprasad Shenai break; 1761812034f1SHariprasad Shenai case SCTP_V4_FLOW: 1762812034f1SHariprasad Shenai case AH_ESP_V4_FLOW: 1763812034f1SHariprasad Shenai case IPV4_FLOW: 1764812034f1SHariprasad Shenai if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) 1765812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST; 1766812034f1SHariprasad Shenai break; 1767812034f1SHariprasad Shenai case TCP_V6_FLOW: 1768812034f1SHariprasad Shenai if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) 1769812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST | 1770812034f1SHariprasad Shenai RXH_L4_B_0_1 | RXH_L4_B_2_3; 1771812034f1SHariprasad Shenai else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) 1772812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST; 1773812034f1SHariprasad Shenai break; 1774812034f1SHariprasad Shenai case UDP_V6_FLOW: 1775812034f1SHariprasad Shenai if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && 1776812034f1SHariprasad Shenai (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) 1777812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST | 1778812034f1SHariprasad Shenai RXH_L4_B_0_1 | RXH_L4_B_2_3; 1779812034f1SHariprasad Shenai else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) 1780812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST; 1781812034f1SHariprasad Shenai break; 1782812034f1SHariprasad Shenai case SCTP_V6_FLOW: 1783812034f1SHariprasad Shenai case AH_ESP_V6_FLOW: 1784812034f1SHariprasad Shenai case IPV6_FLOW: 1785812034f1SHariprasad Shenai if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) 1786812034f1SHariprasad Shenai info->data = RXH_IP_SRC | RXH_IP_DST; 1787812034f1SHariprasad Shenai break; 1788812034f1SHariprasad Shenai } 1789812034f1SHariprasad Shenai return 0; 1790812034f1SHariprasad Shenai } 1791812034f1SHariprasad Shenai case ETHTOOL_GRXRINGS: 1792812034f1SHariprasad Shenai info->data = pi->nqsets; 1793812034f1SHariprasad Shenai return 0; 179427ee2993SVishal Kulkarni case ETHTOOL_GRXCLSRLCNT: 179527ee2993SVishal Kulkarni info->rule_cnt = 179627ee2993SVishal Kulkarni adap->ethtool_filters->port[pi->port_id].in_use; 179727ee2993SVishal Kulkarni return 0; 179827ee2993SVishal Kulkarni case ETHTOOL_GRXCLSRULE: 179927ee2993SVishal Kulkarni return cxgb4_ntuple_get_filter(dev, info, info->fs.location); 180027ee2993SVishal Kulkarni case ETHTOOL_GRXCLSRLALL: 180127ee2993SVishal Kulkarni info->data = adap->ethtool_filters->nentries; 180227ee2993SVishal Kulkarni while (count < info->rule_cnt) { 180327ee2993SVishal Kulkarni ret = cxgb4_ntuple_get_filter(dev, info, index); 180427ee2993SVishal Kulkarni if (!ret) 180527ee2993SVishal Kulkarni rules[count++] = index; 180627ee2993SVishal Kulkarni index++; 1807812034f1SHariprasad Shenai } 180827ee2993SVishal Kulkarni return 0; 180927ee2993SVishal Kulkarni } 181027ee2993SVishal Kulkarni 1811812034f1SHariprasad Shenai return -EOPNOTSUPP; 1812812034f1SHariprasad Shenai } 1813812034f1SHariprasad Shenai 1814db43b30cSVishal Kulkarni static int cxgb4_ntuple_del_filter(struct net_device *dev, 1815db43b30cSVishal Kulkarni struct ethtool_rxnfc *cmd) 1816db43b30cSVishal Kulkarni { 1817db43b30cSVishal Kulkarni struct cxgb4_ethtool_filter_info *filter_info; 1818db43b30cSVishal Kulkarni struct adapter *adapter = netdev2adap(dev); 1819db43b30cSVishal Kulkarni struct port_info *pi = netdev_priv(dev); 1820db43b30cSVishal Kulkarni struct filter_entry *f; 1821db43b30cSVishal Kulkarni u32 filter_id; 1822db43b30cSVishal Kulkarni int ret; 1823db43b30cSVishal Kulkarni 1824db43b30cSVishal Kulkarni if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) 1825db43b30cSVishal Kulkarni return -EAGAIN; /* can still change nfilters */ 1826db43b30cSVishal Kulkarni 1827db43b30cSVishal Kulkarni if (!adapter->ethtool_filters) 1828db43b30cSVishal Kulkarni return -EOPNOTSUPP; 1829db43b30cSVishal Kulkarni 1830db43b30cSVishal Kulkarni if (cmd->fs.location >= adapter->ethtool_filters->nentries) { 1831db43b30cSVishal Kulkarni dev_err(adapter->pdev_dev, 1832db43b30cSVishal Kulkarni "Location must be < %u", 1833db43b30cSVishal Kulkarni adapter->ethtool_filters->nentries); 1834db43b30cSVishal Kulkarni return -ERANGE; 1835db43b30cSVishal Kulkarni } 1836db43b30cSVishal Kulkarni 1837db43b30cSVishal Kulkarni filter_info = &adapter->ethtool_filters->port[pi->port_id]; 1838db43b30cSVishal Kulkarni 1839db43b30cSVishal Kulkarni if (!test_bit(cmd->fs.location, filter_info->bmap)) 1840db43b30cSVishal Kulkarni return -ENOENT; 1841db43b30cSVishal Kulkarni 1842db43b30cSVishal Kulkarni filter_id = filter_info->loc_array[cmd->fs.location]; 1843db43b30cSVishal Kulkarni f = cxgb4_get_filter_entry(adapter, filter_id); 1844db43b30cSVishal Kulkarni 184509427c19SRahul Lakkireddy if (f->fs.prio) 184609427c19SRahul Lakkireddy filter_id -= adapter->tids.hpftid_base; 184709427c19SRahul Lakkireddy else if (!f->fs.hash) 184809427c19SRahul Lakkireddy filter_id -= (adapter->tids.ftid_base - adapter->tids.nhpftids); 184909427c19SRahul Lakkireddy 1850db43b30cSVishal Kulkarni ret = cxgb4_flow_rule_destroy(dev, f->fs.tc_prio, &f->fs, filter_id); 1851db43b30cSVishal Kulkarni if (ret) 1852db43b30cSVishal Kulkarni goto err; 1853db43b30cSVishal Kulkarni 1854db43b30cSVishal Kulkarni clear_bit(cmd->fs.location, filter_info->bmap); 1855db43b30cSVishal Kulkarni filter_info->in_use--; 1856db43b30cSVishal Kulkarni 1857db43b30cSVishal Kulkarni err: 1858db43b30cSVishal Kulkarni return ret; 1859db43b30cSVishal Kulkarni } 1860db43b30cSVishal Kulkarni 1861c8729cacSVishal Kulkarni /* Add Ethtool n-tuple filters. */ 1862c8729cacSVishal Kulkarni static int cxgb4_ntuple_set_filter(struct net_device *netdev, 1863c8729cacSVishal Kulkarni struct ethtool_rxnfc *cmd) 1864c8729cacSVishal Kulkarni { 1865c8729cacSVishal Kulkarni struct ethtool_rx_flow_spec_input input = {}; 1866c8729cacSVishal Kulkarni struct cxgb4_ethtool_filter_info *filter_info; 1867c8729cacSVishal Kulkarni struct adapter *adapter = netdev2adap(netdev); 1868c8729cacSVishal Kulkarni struct port_info *pi = netdev_priv(netdev); 1869c8729cacSVishal Kulkarni struct ch_filter_specification fs; 1870c8729cacSVishal Kulkarni struct ethtool_rx_flow_rule *flow; 1871c8729cacSVishal Kulkarni u32 tid; 1872c8729cacSVishal Kulkarni int ret; 1873c8729cacSVishal Kulkarni 1874c8729cacSVishal Kulkarni if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) 1875c8729cacSVishal Kulkarni return -EAGAIN; /* can still change nfilters */ 1876c8729cacSVishal Kulkarni 1877c8729cacSVishal Kulkarni if (!adapter->ethtool_filters) 1878c8729cacSVishal Kulkarni return -EOPNOTSUPP; 1879c8729cacSVishal Kulkarni 1880c8729cacSVishal Kulkarni if (cmd->fs.location >= adapter->ethtool_filters->nentries) { 1881c8729cacSVishal Kulkarni dev_err(adapter->pdev_dev, 1882c8729cacSVishal Kulkarni "Location must be < %u", 1883c8729cacSVishal Kulkarni adapter->ethtool_filters->nentries); 1884c8729cacSVishal Kulkarni return -ERANGE; 1885c8729cacSVishal Kulkarni } 1886c8729cacSVishal Kulkarni 1887c8729cacSVishal Kulkarni if (test_bit(cmd->fs.location, 1888c8729cacSVishal Kulkarni adapter->ethtool_filters->port[pi->port_id].bmap)) 1889c8729cacSVishal Kulkarni return -EEXIST; 1890c8729cacSVishal Kulkarni 1891c8729cacSVishal Kulkarni memset(&fs, 0, sizeof(fs)); 1892c8729cacSVishal Kulkarni 1893c8729cacSVishal Kulkarni input.fs = &cmd->fs; 1894c8729cacSVishal Kulkarni flow = ethtool_rx_flow_rule_create(&input); 1895c8729cacSVishal Kulkarni if (IS_ERR(flow)) { 1896c8729cacSVishal Kulkarni ret = PTR_ERR(flow); 1897c8729cacSVishal Kulkarni goto exit; 1898c8729cacSVishal Kulkarni } 1899c8729cacSVishal Kulkarni 1900c8729cacSVishal Kulkarni fs.hitcnts = 1; 1901c8729cacSVishal Kulkarni 1902c8729cacSVishal Kulkarni ret = cxgb4_flow_rule_replace(netdev, flow->rule, cmd->fs.location, 1903c8729cacSVishal Kulkarni NULL, &fs, &tid); 1904c8729cacSVishal Kulkarni if (ret) 1905c8729cacSVishal Kulkarni goto free; 1906c8729cacSVishal Kulkarni 1907c8729cacSVishal Kulkarni filter_info = &adapter->ethtool_filters->port[pi->port_id]; 1908c8729cacSVishal Kulkarni 190909427c19SRahul Lakkireddy if (fs.prio) 191009427c19SRahul Lakkireddy tid += adapter->tids.hpftid_base; 191109427c19SRahul Lakkireddy else if (!fs.hash) 191209427c19SRahul Lakkireddy tid += (adapter->tids.ftid_base - adapter->tids.nhpftids); 191309427c19SRahul Lakkireddy 1914c8729cacSVishal Kulkarni filter_info->loc_array[cmd->fs.location] = tid; 1915c8729cacSVishal Kulkarni set_bit(cmd->fs.location, filter_info->bmap); 1916c8729cacSVishal Kulkarni filter_info->in_use++; 1917c8729cacSVishal Kulkarni 1918c8729cacSVishal Kulkarni free: 1919c8729cacSVishal Kulkarni ethtool_rx_flow_rule_destroy(flow); 1920c8729cacSVishal Kulkarni exit: 1921c8729cacSVishal Kulkarni return ret; 1922c8729cacSVishal Kulkarni } 1923c8729cacSVishal Kulkarni 1924c8729cacSVishal Kulkarni static int set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 1925c8729cacSVishal Kulkarni { 1926c8729cacSVishal Kulkarni int ret = -EOPNOTSUPP; 1927c8729cacSVishal Kulkarni 1928c8729cacSVishal Kulkarni switch (cmd->cmd) { 1929c8729cacSVishal Kulkarni case ETHTOOL_SRXCLSRLINS: 1930c8729cacSVishal Kulkarni ret = cxgb4_ntuple_set_filter(dev, cmd); 1931c8729cacSVishal Kulkarni break; 1932db43b30cSVishal Kulkarni case ETHTOOL_SRXCLSRLDEL: 1933db43b30cSVishal Kulkarni ret = cxgb4_ntuple_del_filter(dev, cmd); 1934db43b30cSVishal Kulkarni break; 1935c8729cacSVishal Kulkarni default: 1936c8729cacSVishal Kulkarni break; 1937c8729cacSVishal Kulkarni } 1938c8729cacSVishal Kulkarni 1939c8729cacSVishal Kulkarni return ret; 1940c8729cacSVishal Kulkarni } 1941c8729cacSVishal Kulkarni 1942ad75b7d3SRahul Lakkireddy static int set_dump(struct net_device *dev, struct ethtool_dump *eth_dump) 1943ad75b7d3SRahul Lakkireddy { 1944ad75b7d3SRahul Lakkireddy struct adapter *adapter = netdev2adap(dev); 1945ad75b7d3SRahul Lakkireddy u32 len = 0; 1946ad75b7d3SRahul Lakkireddy 1947ad75b7d3SRahul Lakkireddy len = sizeof(struct cudbg_hdr) + 1948ad75b7d3SRahul Lakkireddy sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY; 1949ad75b7d3SRahul Lakkireddy len += cxgb4_get_dump_length(adapter, eth_dump->flag); 1950ad75b7d3SRahul Lakkireddy 1951ad75b7d3SRahul Lakkireddy adapter->eth_dump.flag = eth_dump->flag; 1952ad75b7d3SRahul Lakkireddy adapter->eth_dump.len = len; 1953ad75b7d3SRahul Lakkireddy return 0; 1954ad75b7d3SRahul Lakkireddy } 1955ad75b7d3SRahul Lakkireddy 1956ad75b7d3SRahul Lakkireddy static int get_dump_flag(struct net_device *dev, struct ethtool_dump *eth_dump) 1957ad75b7d3SRahul Lakkireddy { 1958ad75b7d3SRahul Lakkireddy struct adapter *adapter = netdev2adap(dev); 1959ad75b7d3SRahul Lakkireddy 1960ad75b7d3SRahul Lakkireddy eth_dump->flag = adapter->eth_dump.flag; 1961ad75b7d3SRahul Lakkireddy eth_dump->len = adapter->eth_dump.len; 1962ad75b7d3SRahul Lakkireddy eth_dump->version = adapter->eth_dump.version; 1963ad75b7d3SRahul Lakkireddy return 0; 1964ad75b7d3SRahul Lakkireddy } 1965ad75b7d3SRahul Lakkireddy 1966ad75b7d3SRahul Lakkireddy static int get_dump_data(struct net_device *dev, struct ethtool_dump *eth_dump, 1967ad75b7d3SRahul Lakkireddy void *buf) 1968ad75b7d3SRahul Lakkireddy { 1969ad75b7d3SRahul Lakkireddy struct adapter *adapter = netdev2adap(dev); 1970ad75b7d3SRahul Lakkireddy u32 len = 0; 1971ad75b7d3SRahul Lakkireddy int ret = 0; 1972ad75b7d3SRahul Lakkireddy 1973ad75b7d3SRahul Lakkireddy if (adapter->eth_dump.flag == CXGB4_ETH_DUMP_NONE) 1974ad75b7d3SRahul Lakkireddy return -ENOENT; 1975ad75b7d3SRahul Lakkireddy 1976ad75b7d3SRahul Lakkireddy len = sizeof(struct cudbg_hdr) + 1977ad75b7d3SRahul Lakkireddy sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY; 1978ad75b7d3SRahul Lakkireddy len += cxgb4_get_dump_length(adapter, adapter->eth_dump.flag); 1979ad75b7d3SRahul Lakkireddy if (eth_dump->len < len) 1980ad75b7d3SRahul Lakkireddy return -ENOMEM; 1981ad75b7d3SRahul Lakkireddy 1982ad75b7d3SRahul Lakkireddy ret = cxgb4_cudbg_collect(adapter, buf, &len, adapter->eth_dump.flag); 1983ad75b7d3SRahul Lakkireddy if (ret) 1984ad75b7d3SRahul Lakkireddy return ret; 1985ad75b7d3SRahul Lakkireddy 1986ad75b7d3SRahul Lakkireddy eth_dump->flag = adapter->eth_dump.flag; 1987ad75b7d3SRahul Lakkireddy eth_dump->len = len; 1988ad75b7d3SRahul Lakkireddy eth_dump->version = adapter->eth_dump.version; 1989ad75b7d3SRahul Lakkireddy return 0; 1990ad75b7d3SRahul Lakkireddy } 1991ad75b7d3SRahul Lakkireddy 1992f56ec676SArjun Vynipadath static int cxgb4_get_module_info(struct net_device *dev, 1993f56ec676SArjun Vynipadath struct ethtool_modinfo *modinfo) 1994f56ec676SArjun Vynipadath { 1995f56ec676SArjun Vynipadath struct port_info *pi = netdev_priv(dev); 1996f56ec676SArjun Vynipadath u8 sff8472_comp, sff_diag_type, sff_rev; 1997f56ec676SArjun Vynipadath struct adapter *adapter = pi->adapter; 1998f56ec676SArjun Vynipadath int ret; 1999f56ec676SArjun Vynipadath 2000f56ec676SArjun Vynipadath if (!t4_is_inserted_mod_type(pi->mod_type)) 2001f56ec676SArjun Vynipadath return -EINVAL; 2002f56ec676SArjun Vynipadath 2003f56ec676SArjun Vynipadath switch (pi->port_type) { 2004f56ec676SArjun Vynipadath case FW_PORT_TYPE_SFP: 2005f56ec676SArjun Vynipadath case FW_PORT_TYPE_QSA: 2006f56ec676SArjun Vynipadath case FW_PORT_TYPE_SFP28: 2007f56ec676SArjun Vynipadath ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 2008f56ec676SArjun Vynipadath I2C_DEV_ADDR_A0, SFF_8472_COMP_ADDR, 2009f56ec676SArjun Vynipadath SFF_8472_COMP_LEN, &sff8472_comp); 2010f56ec676SArjun Vynipadath if (ret) 2011f56ec676SArjun Vynipadath return ret; 2012f56ec676SArjun Vynipadath ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 2013f56ec676SArjun Vynipadath I2C_DEV_ADDR_A0, SFP_DIAG_TYPE_ADDR, 2014f56ec676SArjun Vynipadath SFP_DIAG_TYPE_LEN, &sff_diag_type); 2015f56ec676SArjun Vynipadath if (ret) 2016f56ec676SArjun Vynipadath return ret; 2017f56ec676SArjun Vynipadath 2018f56ec676SArjun Vynipadath if (!sff8472_comp || (sff_diag_type & 4)) { 2019f56ec676SArjun Vynipadath modinfo->type = ETH_MODULE_SFF_8079; 2020f56ec676SArjun Vynipadath modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 2021f56ec676SArjun Vynipadath } else { 2022f56ec676SArjun Vynipadath modinfo->type = ETH_MODULE_SFF_8472; 2023f56ec676SArjun Vynipadath modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 2024f56ec676SArjun Vynipadath } 2025f56ec676SArjun Vynipadath break; 2026f56ec676SArjun Vynipadath 2027f56ec676SArjun Vynipadath case FW_PORT_TYPE_QSFP: 2028f56ec676SArjun Vynipadath case FW_PORT_TYPE_QSFP_10G: 2029f56ec676SArjun Vynipadath case FW_PORT_TYPE_CR_QSFP: 2030f56ec676SArjun Vynipadath case FW_PORT_TYPE_CR2_QSFP: 2031f56ec676SArjun Vynipadath case FW_PORT_TYPE_CR4_QSFP: 2032f56ec676SArjun Vynipadath ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 2033f56ec676SArjun Vynipadath I2C_DEV_ADDR_A0, SFF_REV_ADDR, 2034f56ec676SArjun Vynipadath SFF_REV_LEN, &sff_rev); 2035f56ec676SArjun Vynipadath /* For QSFP type ports, revision value >= 3 2036f56ec676SArjun Vynipadath * means the SFP is 8636 compliant. 2037f56ec676SArjun Vynipadath */ 2038f56ec676SArjun Vynipadath if (ret) 2039f56ec676SArjun Vynipadath return ret; 2040f56ec676SArjun Vynipadath if (sff_rev >= 0x3) { 2041f56ec676SArjun Vynipadath modinfo->type = ETH_MODULE_SFF_8636; 2042f56ec676SArjun Vynipadath modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 2043f56ec676SArjun Vynipadath } else { 2044f56ec676SArjun Vynipadath modinfo->type = ETH_MODULE_SFF_8436; 2045f56ec676SArjun Vynipadath modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 2046f56ec676SArjun Vynipadath } 2047f56ec676SArjun Vynipadath break; 2048f56ec676SArjun Vynipadath 2049f56ec676SArjun Vynipadath default: 2050f56ec676SArjun Vynipadath return -EINVAL; 2051f56ec676SArjun Vynipadath } 2052f56ec676SArjun Vynipadath 2053f56ec676SArjun Vynipadath return 0; 2054f56ec676SArjun Vynipadath } 2055f56ec676SArjun Vynipadath 2056f56ec676SArjun Vynipadath static int cxgb4_get_module_eeprom(struct net_device *dev, 2057f56ec676SArjun Vynipadath struct ethtool_eeprom *eprom, u8 *data) 2058f56ec676SArjun Vynipadath { 2059f56ec676SArjun Vynipadath int ret = 0, offset = eprom->offset, len = eprom->len; 2060f56ec676SArjun Vynipadath struct port_info *pi = netdev_priv(dev); 2061f56ec676SArjun Vynipadath struct adapter *adapter = pi->adapter; 2062f56ec676SArjun Vynipadath 2063f56ec676SArjun Vynipadath memset(data, 0, eprom->len); 2064f56ec676SArjun Vynipadath if (offset + len <= I2C_PAGE_SIZE) 2065f56ec676SArjun Vynipadath return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 2066f56ec676SArjun Vynipadath I2C_DEV_ADDR_A0, offset, len, data); 2067f56ec676SArjun Vynipadath 2068f56ec676SArjun Vynipadath /* offset + len spans 0xa0 and 0xa1 pages */ 2069f56ec676SArjun Vynipadath if (offset <= I2C_PAGE_SIZE) { 2070f56ec676SArjun Vynipadath /* read 0xa0 page */ 2071f56ec676SArjun Vynipadath len = I2C_PAGE_SIZE - offset; 2072f56ec676SArjun Vynipadath ret = t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, 2073f56ec676SArjun Vynipadath I2C_DEV_ADDR_A0, offset, len, data); 2074f56ec676SArjun Vynipadath if (ret) 2075f56ec676SArjun Vynipadath return ret; 2076f56ec676SArjun Vynipadath offset = I2C_PAGE_SIZE; 2077f56ec676SArjun Vynipadath /* Remaining bytes to be read from second page = 2078f56ec676SArjun Vynipadath * Total length - bytes read from first page 2079f56ec676SArjun Vynipadath */ 2080f56ec676SArjun Vynipadath len = eprom->len - len; 2081f56ec676SArjun Vynipadath } 2082f56ec676SArjun Vynipadath /* Read additional optical diagnostics from page 0xa2 if supported */ 2083f56ec676SArjun Vynipadath return t4_i2c_rd(adapter, adapter->mbox, pi->tx_chan, I2C_DEV_ADDR_A2, 2084f56ec676SArjun Vynipadath offset, len, &data[eprom->len - len]); 2085f56ec676SArjun Vynipadath } 2086f56ec676SArjun Vynipadath 2087c90d1604SArjun Vynipadath static u32 cxgb4_get_priv_flags(struct net_device *netdev) 2088c90d1604SArjun Vynipadath { 2089c90d1604SArjun Vynipadath struct port_info *pi = netdev_priv(netdev); 2090c90d1604SArjun Vynipadath struct adapter *adapter = pi->adapter; 2091c90d1604SArjun Vynipadath 2092c90d1604SArjun Vynipadath return (adapter->eth_flags | pi->eth_flags); 2093c90d1604SArjun Vynipadath } 2094c90d1604SArjun Vynipadath 2095c90d1604SArjun Vynipadath /** 2096c90d1604SArjun Vynipadath * set_flags - set/unset specified flags if passed in new_flags 2097c90d1604SArjun Vynipadath * @cur_flags: pointer to current flags 2098c90d1604SArjun Vynipadath * @new_flags: new incoming flags 2099c90d1604SArjun Vynipadath * @flags: set of flags to set/unset 2100c90d1604SArjun Vynipadath */ 2101c90d1604SArjun Vynipadath static inline void set_flags(u32 *cur_flags, u32 new_flags, u32 flags) 2102c90d1604SArjun Vynipadath { 2103c90d1604SArjun Vynipadath *cur_flags = (*cur_flags & ~flags) | (new_flags & flags); 2104c90d1604SArjun Vynipadath } 2105c90d1604SArjun Vynipadath 2106c90d1604SArjun Vynipadath static int cxgb4_set_priv_flags(struct net_device *netdev, u32 flags) 2107c90d1604SArjun Vynipadath { 2108c90d1604SArjun Vynipadath struct port_info *pi = netdev_priv(netdev); 2109c90d1604SArjun Vynipadath struct adapter *adapter = pi->adapter; 2110c90d1604SArjun Vynipadath 2111c90d1604SArjun Vynipadath set_flags(&adapter->eth_flags, flags, PRIV_FLAGS_ADAP); 2112c90d1604SArjun Vynipadath set_flags(&pi->eth_flags, flags, PRIV_FLAGS_PORT); 2113c90d1604SArjun Vynipadath 2114c90d1604SArjun Vynipadath return 0; 2115c90d1604SArjun Vynipadath } 2116c90d1604SArjun Vynipadath 21177235ffaeSVishal Kulkarni static void cxgb4_lb_test(struct net_device *netdev, u64 *lb_status) 21187235ffaeSVishal Kulkarni { 21197235ffaeSVishal Kulkarni int dev_state = netif_running(netdev); 21207235ffaeSVishal Kulkarni 21217235ffaeSVishal Kulkarni if (dev_state) { 21227235ffaeSVishal Kulkarni netif_tx_stop_all_queues(netdev); 21237235ffaeSVishal Kulkarni netif_carrier_off(netdev); 21247235ffaeSVishal Kulkarni } 21257235ffaeSVishal Kulkarni 21267235ffaeSVishal Kulkarni *lb_status = cxgb4_selftest_lb_pkt(netdev); 21277235ffaeSVishal Kulkarni 21287235ffaeSVishal Kulkarni if (dev_state) { 21297235ffaeSVishal Kulkarni netif_tx_start_all_queues(netdev); 21307235ffaeSVishal Kulkarni netif_carrier_on(netdev); 21317235ffaeSVishal Kulkarni } 21327235ffaeSVishal Kulkarni } 21337235ffaeSVishal Kulkarni 21347235ffaeSVishal Kulkarni static void cxgb4_self_test(struct net_device *netdev, 21357235ffaeSVishal Kulkarni struct ethtool_test *eth_test, u64 *data) 21367235ffaeSVishal Kulkarni { 21377235ffaeSVishal Kulkarni struct port_info *pi = netdev_priv(netdev); 21387235ffaeSVishal Kulkarni struct adapter *adap = pi->adapter; 21397235ffaeSVishal Kulkarni 21407235ffaeSVishal Kulkarni memset(data, 0, sizeof(u64) * CXGB4_ETHTOOL_MAX_TEST); 21417235ffaeSVishal Kulkarni 2142fd4ec076SRahul Lakkireddy if (!(adap->flags & CXGB4_FULL_INIT_DONE) || 2143fd4ec076SRahul Lakkireddy !(adap->flags & CXGB4_FW_OK)) { 21447235ffaeSVishal Kulkarni eth_test->flags |= ETH_TEST_FL_FAILED; 21457235ffaeSVishal Kulkarni return; 21467235ffaeSVishal Kulkarni } 21477235ffaeSVishal Kulkarni 2148fd4ec076SRahul Lakkireddy if (eth_test->flags & ETH_TEST_FL_OFFLINE) 21497235ffaeSVishal Kulkarni cxgb4_lb_test(netdev, &data[CXGB4_ETHTOOL_LB_TEST]); 21507235ffaeSVishal Kulkarni 21517235ffaeSVishal Kulkarni if (data[CXGB4_ETHTOOL_LB_TEST]) 21527235ffaeSVishal Kulkarni eth_test->flags |= ETH_TEST_FL_FAILED; 21537235ffaeSVishal Kulkarni } 21547235ffaeSVishal Kulkarni 2155812034f1SHariprasad Shenai static const struct ethtool_ops cxgb_ethtool_ops = { 21565608c641SJakub Kicinski .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 21575608c641SJakub Kicinski ETHTOOL_COALESCE_RX_MAX_FRAMES | 21585608c641SJakub Kicinski ETHTOOL_COALESCE_TX_USECS_IRQ | 21595608c641SJakub Kicinski ETHTOOL_COALESCE_USE_ADAPTIVE_RX, 2160eb97ad99SGanesh Goudar .get_link_ksettings = get_link_ksettings, 2161eb97ad99SGanesh Goudar .set_link_ksettings = set_link_ksettings, 21627fece840SCasey Leedom .get_fecparam = get_fecparam, 21637fece840SCasey Leedom .set_fecparam = set_fecparam, 2164812034f1SHariprasad Shenai .get_drvinfo = get_drvinfo, 2165812034f1SHariprasad Shenai .get_msglevel = get_msglevel, 2166812034f1SHariprasad Shenai .set_msglevel = set_msglevel, 2167812034f1SHariprasad Shenai .get_ringparam = get_sge_param, 2168812034f1SHariprasad Shenai .set_ringparam = set_sge_param, 2169812034f1SHariprasad Shenai .get_coalesce = get_coalesce, 2170812034f1SHariprasad Shenai .set_coalesce = set_coalesce, 2171812034f1SHariprasad Shenai .get_eeprom_len = get_eeprom_len, 2172812034f1SHariprasad Shenai .get_eeprom = get_eeprom, 2173812034f1SHariprasad Shenai .set_eeprom = set_eeprom, 2174812034f1SHariprasad Shenai .get_pauseparam = get_pauseparam, 2175812034f1SHariprasad Shenai .set_pauseparam = set_pauseparam, 2176812034f1SHariprasad Shenai .get_link = ethtool_op_get_link, 2177812034f1SHariprasad Shenai .get_strings = get_strings, 2178812034f1SHariprasad Shenai .set_phys_id = identify_port, 2179812034f1SHariprasad Shenai .nway_reset = restart_autoneg, 2180812034f1SHariprasad Shenai .get_sset_count = get_sset_count, 2181812034f1SHariprasad Shenai .get_ethtool_stats = get_stats, 2182812034f1SHariprasad Shenai .get_regs_len = get_regs_len, 2183812034f1SHariprasad Shenai .get_regs = get_regs, 2184812034f1SHariprasad Shenai .get_rxnfc = get_rxnfc, 2185c8729cacSVishal Kulkarni .set_rxnfc = set_rxnfc, 2186812034f1SHariprasad Shenai .get_rxfh_indir_size = get_rss_table_size, 2187812034f1SHariprasad Shenai .get_rxfh = get_rss_table, 2188812034f1SHariprasad Shenai .set_rxfh = set_rss_table, 21897235ffaeSVishal Kulkarni .self_test = cxgb4_self_test, 2190812034f1SHariprasad Shenai .flash_device = set_flash, 2191ad75b7d3SRahul Lakkireddy .get_ts_info = get_ts_info, 2192ad75b7d3SRahul Lakkireddy .set_dump = set_dump, 2193ad75b7d3SRahul Lakkireddy .get_dump_flag = get_dump_flag, 2194ad75b7d3SRahul Lakkireddy .get_dump_data = get_dump_data, 2195f56ec676SArjun Vynipadath .get_module_info = cxgb4_get_module_info, 2196f56ec676SArjun Vynipadath .get_module_eeprom = cxgb4_get_module_eeprom, 2197c90d1604SArjun Vynipadath .get_priv_flags = cxgb4_get_priv_flags, 2198c90d1604SArjun Vynipadath .set_priv_flags = cxgb4_set_priv_flags, 2199812034f1SHariprasad Shenai }; 2200812034f1SHariprasad Shenai 2201d915c299SVishal Kulkarni void cxgb4_cleanup_ethtool_filters(struct adapter *adap) 2202d915c299SVishal Kulkarni { 2203d915c299SVishal Kulkarni struct cxgb4_ethtool_filter_info *eth_filter_info; 2204d915c299SVishal Kulkarni u8 i; 2205d915c299SVishal Kulkarni 2206d915c299SVishal Kulkarni if (!adap->ethtool_filters) 2207d915c299SVishal Kulkarni return; 2208d915c299SVishal Kulkarni 2209d915c299SVishal Kulkarni eth_filter_info = adap->ethtool_filters->port; 2210d915c299SVishal Kulkarni 2211d915c299SVishal Kulkarni if (eth_filter_info) { 2212d915c299SVishal Kulkarni for (i = 0; i < adap->params.nports; i++) { 2213d915c299SVishal Kulkarni kvfree(eth_filter_info[i].loc_array); 2214d915c299SVishal Kulkarni kfree(eth_filter_info[i].bmap); 2215d915c299SVishal Kulkarni } 2216d915c299SVishal Kulkarni kfree(eth_filter_info); 2217d915c299SVishal Kulkarni } 2218d915c299SVishal Kulkarni 2219d915c299SVishal Kulkarni kfree(adap->ethtool_filters); 2220d915c299SVishal Kulkarni } 2221d915c299SVishal Kulkarni 2222d915c299SVishal Kulkarni int cxgb4_init_ethtool_filters(struct adapter *adap) 2223d915c299SVishal Kulkarni { 2224d915c299SVishal Kulkarni struct cxgb4_ethtool_filter_info *eth_filter_info; 2225d915c299SVishal Kulkarni struct cxgb4_ethtool_filter *eth_filter; 2226d915c299SVishal Kulkarni struct tid_info *tids = &adap->tids; 2227d915c299SVishal Kulkarni u32 nentries, i; 2228d915c299SVishal Kulkarni int ret; 2229d915c299SVishal Kulkarni 2230d915c299SVishal Kulkarni eth_filter = kzalloc(sizeof(*eth_filter), GFP_KERNEL); 2231d915c299SVishal Kulkarni if (!eth_filter) 2232d915c299SVishal Kulkarni return -ENOMEM; 2233d915c299SVishal Kulkarni 2234d915c299SVishal Kulkarni eth_filter_info = kcalloc(adap->params.nports, 2235d915c299SVishal Kulkarni sizeof(*eth_filter_info), 2236d915c299SVishal Kulkarni GFP_KERNEL); 2237d915c299SVishal Kulkarni if (!eth_filter_info) { 2238d915c299SVishal Kulkarni ret = -ENOMEM; 2239d915c299SVishal Kulkarni goto free_eth_filter; 2240d915c299SVishal Kulkarni } 2241d915c299SVishal Kulkarni 2242d915c299SVishal Kulkarni eth_filter->port = eth_filter_info; 2243d915c299SVishal Kulkarni 2244d915c299SVishal Kulkarni nentries = tids->nhpftids + tids->nftids; 2245d915c299SVishal Kulkarni if (is_hashfilter(adap)) 2246d915c299SVishal Kulkarni nentries += tids->nhash + 2247d915c299SVishal Kulkarni (adap->tids.stid_base - adap->tids.tid_base); 2248d915c299SVishal Kulkarni eth_filter->nentries = nentries; 2249d915c299SVishal Kulkarni 2250d915c299SVishal Kulkarni for (i = 0; i < adap->params.nports; i++) { 2251d915c299SVishal Kulkarni eth_filter->port[i].loc_array = kvzalloc(nentries, GFP_KERNEL); 2252d915c299SVishal Kulkarni if (!eth_filter->port[i].loc_array) { 2253d915c299SVishal Kulkarni ret = -ENOMEM; 2254d915c299SVishal Kulkarni goto free_eth_finfo; 2255d915c299SVishal Kulkarni } 2256d915c299SVishal Kulkarni 2257d915c299SVishal Kulkarni eth_filter->port[i].bmap = kcalloc(BITS_TO_LONGS(nentries), 2258d915c299SVishal Kulkarni sizeof(unsigned long), 2259d915c299SVishal Kulkarni GFP_KERNEL); 2260d915c299SVishal Kulkarni if (!eth_filter->port[i].bmap) { 2261d915c299SVishal Kulkarni ret = -ENOMEM; 2262d915c299SVishal Kulkarni goto free_eth_finfo; 2263d915c299SVishal Kulkarni } 2264d915c299SVishal Kulkarni } 2265d915c299SVishal Kulkarni 2266d915c299SVishal Kulkarni adap->ethtool_filters = eth_filter; 2267d915c299SVishal Kulkarni return 0; 2268d915c299SVishal Kulkarni 2269d915c299SVishal Kulkarni free_eth_finfo: 2270d915c299SVishal Kulkarni while (i-- > 0) { 2271d915c299SVishal Kulkarni kfree(eth_filter->port[i].bmap); 2272d915c299SVishal Kulkarni kvfree(eth_filter->port[i].loc_array); 2273d915c299SVishal Kulkarni } 2274d915c299SVishal Kulkarni kfree(eth_filter_info); 2275d915c299SVishal Kulkarni 2276d915c299SVishal Kulkarni free_eth_filter: 2277d915c299SVishal Kulkarni kfree(eth_filter); 2278d915c299SVishal Kulkarni 2279d915c299SVishal Kulkarni return ret; 2280d915c299SVishal Kulkarni } 2281d915c299SVishal Kulkarni 2282812034f1SHariprasad Shenai void cxgb4_set_ethtool_ops(struct net_device *netdev) 2283812034f1SHariprasad Shenai { 2284812034f1SHariprasad Shenai netdev->ethtool_ops = &cxgb_ethtool_ops; 2285812034f1SHariprasad Shenai } 2286